11#ifndef PBAT_FEM_SHAPEFUNCTIONS_H
12#define PBAT_FEM_SHAPEFUNCTIONS_H
26#include <tbb/parallel_for.h>
39template <CElement TElement,
int QuadratureOrder, common::CFloatingPo
int TScalar = Scalar>
43 TElement::template QuadratureType<QuadratureOrder, TScalar>::kPoints>
45 using QuadratureRuleType =
typename TElement::template QuadratureType<QuadratureOrder, TScalar>;
46 using ElementType = TElement;
48 .reshaped(QuadratureRuleType::kDims + 1, QuadratureRuleType::kPoints)
49 .template bottomRows<QuadratureRuleType::kDims>();
50 Eigen::Matrix<TScalar, ElementType::kNodes, QuadratureRuleType::kPoints> Ng{};
51 for (
auto g = 0; g < QuadratureRuleType::kPoints; ++g)
53 Ng.col(g) = ElementType::N(Xg.col(g));
69template <CElement TElement,
int QuadratureOrder, common::CFloatingPo
int TScalar,
class TDerivedE>
71 -> Eigen::SparseMatrix<TScalar, Eigen::RowMajor, typename TDerivedE::Scalar>
73 PBAT_PROFILE_NAMED_SCOPE(
"pbat.fem.ShapeFunctionMatrix");
74 using ElementType = TElement;
75 using ScalarType = TScalar;
76 using IndexType =
typename TDerivedE::Scalar;
77 using IndexVectorType = Eigen::Vector<IndexType, Eigen::Dynamic>;
79 auto const nElements = E.cols();
80 auto const nQuadPointsPerElement = Ng.cols();
81 auto const m = nQuadPointsPerElement * nElements;
82 auto const n = nNodes;
83 auto constexpr kNodesPerElement = ElementType::kNodes;
84 Eigen::SparseMatrix<ScalarType, Eigen::RowMajor, IndexType> N(m, n);
85 N.reserve(IndexVectorType::Constant(m, kNodesPerElement));
86 for (
auto e = 0; e < nElements; ++e)
88 auto const nodes = E.col(e);
89 for (
auto g = 0; g < nQuadPointsPerElement; ++g)
91 auto const row = e * nQuadPointsPerElement + g;
92 for (
auto i = 0; i < Ng.rows(); ++i)
94 auto const col = nodes(i);
95 N.insert(row, col) = Ng(i, g);
110template <
int QuadratureOrder, CMesh TMesh>
112 -> Eigen::SparseMatrix<typename TMesh::ScalarType, Eigen::RowMajor, typename TMesh::IndexType>
115 typename TMesh::ElementType,
117 typename TMesh::ScalarType>(mesh.E, mesh.X.cols());
138 Eigen::DenseBase<TDerivedE>
const& E,
140 Eigen::MatrixBase<TDerivedXi>
const& Xi)
141 -> Eigen::SparseMatrix<typename TDerivedXi::Scalar, Eigen::RowMajor, TIndex>
143 PBAT_PROFILE_NAMED_SCOPE(
"pbat.fem.ShapeFunctionMatrix");
144 using ElementType = TElement;
145 using ScalarType =
typename TDerivedXi::Scalar;
146 using IndexType = TIndex;
147 using IndexVectorType = Eigen::Vector<IndexType, Eigen::Dynamic>;
148 using SparseMatrixType = Eigen::SparseMatrix<ScalarType, Eigen::RowMajor, IndexType>;
149 auto const numberOfQuadPoints = Xi.cols();
150 auto constexpr kNodesPerElement = ElementType::kNodes;
151 SparseMatrixType N(numberOfQuadPoints, nNodes);
152 N.reserve(IndexVectorType::Constant(numberOfQuadPoints, kNodesPerElement));
153 for (
auto g = 0; g < numberOfQuadPoints; ++g)
155 auto const nodes = E.col(g);
156 auto Ng = ElementType::N(Xi.col(g));
157 for (
auto i = 0; i < kNodesPerElement; ++i)
159 N.insert(g, nodes(i)) = Ng(i);
176template <CMesh TMesh,
class TDerivedEg,
class TDerivedXi>
179 Eigen::DenseBase<TDerivedEg>
const& eg,
180 Eigen::MatrixBase<TDerivedXi>
const& Xi)
181 -> Eigen::SparseMatrix<typename TMesh::ScalarType, Eigen::RowMajor, typename TMesh::IndexType>
183 using ScalarType =
typename TMesh::ScalarType;
184 using IndexType =
typename TMesh::IndexType;
186 std::is_same_v<ScalarType, typename TDerivedXi::Scalar>,
187 "Scalar type of Xi must match mesh scalar type");
189 mesh.E(Eigen::placeholders::all, eg.derived()),
190 static_cast<IndexType
>(mesh.X.cols()),
202template <CElement TElement,
class TDerivedXi>
204 -> Eigen::Matrix<typename TDerivedXi::Scalar, TElement::kNodes, Eigen::Dynamic>
206 PBAT_PROFILE_NAMED_SCOPE(
"pbat.fem.ShapeFunctionsAt");
207 using ElementType = TElement;
208 using ScalarType =
typename TDerivedXi::Scalar;
209 using MatrixType = Eigen::Matrix<ScalarType, ElementType::kNodes, Eigen::Dynamic>;
210 if (Xi.rows() != ElementType::kDims)
212 std::string
const what = fmt::format(
213 "Expected evaluation points in d={} dimensions, but got Xi.rows()={}",
216 throw std::invalid_argument(what);
218 MatrixType N(ElementType::kNodes, Xi.cols());
220 N.col(i) = ElementType::N(Xi.col(i));
266template <CElement TElement,
class TDerivedXi,
class TDerivedX>
268 Eigen::MatrixBase<TDerivedXi>
const& Xi,
269 Eigen::MatrixBase<TDerivedX>
const& X)
270 -> Eigen::Matrix<typename TDerivedX::Scalar, TElement::kNodes, TDerivedX::RowsAtCompileTime>
272 auto constexpr kInputDims = TElement::kDims;
273 auto constexpr kOutputDims = TDerivedX::RowsAtCompileTime;
274 auto constexpr kNodes = TElement::kNodes;
275 using ScalarType =
typename TDerivedX::Scalar;
277 std::is_same_v<ScalarType, typename TDerivedXi::Scalar>,
278 "Scalar type of Xi must match X's scalar type");
279 static_assert(kOutputDims != Eigen::Dynamic,
"Rows of X must be fixed at compile time");
281 Eigen::Matrix<ScalarType, kNodes, kInputDims>
const GN = TElement::GradN(Xi);
282 Eigen::Matrix<ScalarType, kNodes, kOutputDims> GP;
283 Eigen::Matrix<ScalarType, kOutputDims, kInputDims> J = X * GN;
285 bool constexpr bIsJacobianSquare = kInputDims == kOutputDims;
286 if constexpr (bIsJacobianSquare)
288 GP.transpose() = J.transpose().fullPivLu().solve(GN.transpose());
293 J.transpose().template jacobiSvd<Eigen::ComputeThinU | Eigen::ComputeThinV>().solve(
322 Eigen::MatrixBase<TDerivedE>
const& E,
323 Eigen::MatrixBase<TDerivedX>
const& X)
324 -> Eigen::Matrix<TScalar, TElement::kNodes, Eigen::Dynamic>
326 PBAT_PROFILE_NAMED_SCOPE(
"pbat.fem.ShapeFunctionGradients");
327 using ScalarType = TScalar;
328 using QuadratureRuleType =
329 typename TElement::template QuadratureType<QuadratureOrder, ScalarType>;
330 using ElementType = TElement;
331 using MatrixType = Eigen::Matrix<ScalarType, ElementType::kNodes, Eigen::Dynamic>;
333 .reshaped(QuadratureRuleType::kDims + 1, QuadratureRuleType::kPoints)
334 .template bottomRows<QuadratureRuleType::kDims>();
335 auto const numberOfElements = E.cols();
336 auto constexpr kNodesPerElement = ElementType::kNodes;
337 MatrixType GNe(kNodesPerElement, numberOfElements * Dims * QuadratureRuleType::kPoints);
339 auto const nodes = E.col(e);
340 for (
auto g = 0; g < QuadratureRuleType::kPoints; ++g)
344 X(Eigen::placeholders::all, nodes)
345 .
template topLeftCorner<Dims, kNodesPerElement>());
346 auto constexpr kStride = Dims * QuadratureRuleType::kPoints;
347 GNe.template block<kNodesPerElement, Dims>(0, e * kStride + g * Dims) = GP;
361template <
int QuadratureOrder, CMesh TMesh>
363 -> Eigen::Matrix<typename TMesh::ScalarType, TMesh::ElementType::kNodes, Eigen::Dynamic>
365 using MeshType = TMesh;
366 using ElementType =
typename MeshType::ElementType;
382template <CElement TElement,
int Dims,
class TDerivedEg,
class TDerivedX,
class TDerivedXi>
384 Eigen::DenseBase<TDerivedEg>
const& Eg,
385 Eigen::MatrixBase<TDerivedX>
const& X,
386 Eigen::MatrixBase<TDerivedXi>
const& Xi)
387 -> Eigen::Matrix<typename TDerivedXi::Scalar, TElement::kNodes, Eigen::Dynamic>
389 PBAT_PROFILE_NAMED_SCOPE(
"pbat.fem.ShapeFunctionGradientsAt");
390 using ElementType = TElement;
391 using ScalarType =
typename TDerivedXi::Scalar;
392 using MatrixType = Eigen::Matrix<ScalarType, ElementType::kNodes, Eigen::Dynamic>;
393 if (Eg.cols() != Xi.cols())
395 std::string
const what = fmt::format(
396 "Expected Eg.cols() == Xi.cols(), but got Eg.cols()={} and Xi.cols()={}",
399 throw std::invalid_argument(what);
401 auto const numberOfEvaluationPoints = Xi.cols();
402 MatrixType GNe(ElementType::kNodes, numberOfEvaluationPoints * Dims);
403 tbb::parallel_for(
Index{0},
Index{numberOfEvaluationPoints}, [&](
Index g) {
404 auto const nodes = Eg.col(g);
407 X(Eigen::placeholders::all, nodes).
template topLeftCorner<Dims, ElementType::kNodes>());
408 GNe.template block<ElementType::kNodes, Dims>(0, g * Dims) = GP;
424template <CMesh TMesh,
class TDerivedEg,
class TDerivedXi>
427 Eigen::DenseBase<TDerivedEg>
const& eg,
428 Eigen::MatrixBase<TDerivedXi>
const& Xi)
429 -> Eigen::Matrix<typename TMesh::ScalarType, TMesh::ElementType::kNodes, Eigen::Dynamic>
431 PBAT_PROFILE_NAMED_SCOPE(
"pbat.fem.ShapeFunctionGradientsAt");
432 using ScalarType =
typename TMesh::ScalarType;
433 using MeshType = TMesh;
434 using ElementType =
typename MeshType::ElementType;
436 std::is_same_v<ScalarType, typename TDerivedXi::Scalar>,
437 "Scalar type of Xi must match mesh scalar type");
439 mesh.E(Eigen::placeholders::all, eg.derived()),
Functions to compute jacobians, their determinants, domain quadrature weights and mapping domain to r...
Concepts for common types.
Eigen adaptors for ranges.
Concept for floating-point types.
Definition Concepts.h:56
Concept for integral types.
Definition Concepts.h:45
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
auto ElementShapeFunctions() -> Eigen::Matrix< TScalar, TElement::kNodes, TElement::template QuadratureType< QuadratureOrder, TScalar >::kPoints >
Computes shape functions at element quadrature points for a polynomial quadrature rule of order Quadr...
Definition ShapeFunctions.h:40
auto ShapeFunctionMatrixAt(Eigen::DenseBase< TDerivedE > const &E, TIndex nNodes, Eigen::MatrixBase< TDerivedXi > const &Xi) -> Eigen::SparseMatrix< typename TDerivedXi::Scalar, Eigen::RowMajor, TIndex >
Constructs a shape function matrix for a given mesh, i.e. at the element quadrature points.
Definition ShapeFunctions.h:137
auto ShapeFunctionGradients(Eigen::MatrixBase< TDerivedE > const &E, Eigen::MatrixBase< TDerivedX > const &X) -> Eigen::Matrix< TScalar, TElement::kNodes, Eigen::Dynamic >
Computes nodal shape function gradients at each element quadrature points.
Definition ShapeFunctions.h:321
auto ShapeFunctionMatrix(Eigen::DenseBase< TDerivedE > const &E, Eigen::Index nNodes) -> Eigen::SparseMatrix< TScalar, Eigen::RowMajor, typename TDerivedE::Scalar >
Constructs a shape function matrix for a given mesh, i.e. at the element quadrature points.
Definition ShapeFunctions.h:70
auto ShapeFunctionsAt(Eigen::DenseBase< TDerivedXi > const &Xi) -> Eigen::Matrix< typename TDerivedXi::Scalar, TElement::kNodes, Eigen::Dynamic >
Compute shape functions at the given reference positions.
Definition ShapeFunctions.h:203
auto ShapeFunctionGradientsAt(Eigen::DenseBase< TDerivedEg > const &Eg, Eigen::MatrixBase< TDerivedX > const &X, Eigen::MatrixBase< TDerivedXi > const &Xi) -> Eigen::Matrix< typename TDerivedXi::Scalar, TElement::kNodes, Eigen::Dynamic >
Computes nodal shape function gradients at evaluation points Xi.
Definition ShapeFunctions.h:383
auto ElementShapeFunctionGradients(Eigen::MatrixBase< TDerivedXi > const &Xi, Eigen::MatrixBase< TDerivedX > const &X) -> Eigen::Matrix< typename TDerivedX::Scalar, TElement::kNodes, TDerivedX::RowsAtCompileTime >
Computes gradients of FEM basis functions. Given some FEM function.
Definition ShapeFunctions.h:267
std::ptrdiff_t Index
Index type.
Definition Aliases.h:17
Profiling utilities for the Physics-Based Animation Toolkit (PBAT)