12#ifndef PBAT_FEM_JACOBIAN_H
13#define PBAT_FEM_JACOBIAN_H
18#include <Eigen/Cholesky>
26#include <tbb/parallel_for.h>
44 common::CFloatingPoint TScalar =
typename TDerivedX::Scalar>
46Jacobian(Eigen::MatrixBase<TDerivedX>
const& X, Eigen::MatrixBase<TDerivedx>
const& x)
47 -> Eigen::Matrix<TScalar, TDerivedx::RowsAtCompileTime, TElement::kDims>
50 TDerivedx::ColsAtCompileTime == TElement::kNodes,
51 "x must have the same number of columns as the number of nodes in the element.");
52 auto constexpr kDimsOut = TDerivedx::RowsAtCompileTime;
53 Eigen::Matrix<TScalar, kDimsOut, TElement::kDims>
const J = x * TElement::GradN(X);
67template <
class TDerived>
69 typename TDerived::Scalar
71 using ScalarType =
typename TDerived::Scalar;
72 bool const bIsSquare = J.rows() == J.cols();
73 auto const detJ = bIsSquare ? J.determinant() : J.jacobiSvd().singularValues().prod();
74 ScalarType
constexpr eps = ScalarType(1e-10);
77 throw std::invalid_argument(
"Inverted or singular jacobian");
93template <CElement TElement,
int QuadratureOrder,
class TDerivedE,
class TDerivedX>
97 typename TDerivedX::Scalar,
98 TElement::template QuadratureType<QuadratureOrder, typename TDerivedX::Scalar>::kPoints,
101 PBAT_PROFILE_NAMED_SCOPE(
"pbat.fem.DeterminantOfJacobian");
102 using ScalarType =
typename TDerivedX::Scalar;
103 using ElementType = TElement;
104 using AffineElementType =
typename ElementType::AffineBaseType;
105 using QuadratureRuleType =
106 typename ElementType::template QuadratureType<QuadratureOrder, ScalarType>;
107 using MatrixType = Eigen::Matrix<ScalarType, QuadratureRuleType::kPoints, Eigen::Dynamic>;
108 if (X.rows() < ElementType::kDims)
110 throw std::invalid_argument(
112 "Invalid number of dimensions, expected at least {}, but got {}",
117 .reshaped(QuadratureRuleType::kDims + 1, QuadratureRuleType::kPoints)
118 .template bottomRows<ElementType::kDims>();
119 auto const numberOfElements = E.cols();
120 MatrixType detJe(QuadratureRuleType::kPoints, numberOfElements);
122 auto const nodes = E.col(e);
123 auto const vertices = nodes(ElementType::Vertices);
124 auto constexpr kRowsJ = TDerivedX::RowsAtCompileTime;
125 auto constexpr kColsJ = AffineElementType::kNodes;
126 Eigen::Matrix<ScalarType, kRowsJ, kColsJ>
const Ve = X(Eigen::placeholders::all, vertices);
127 if constexpr (AffineElementType::bHasConstantJacobian)
131 detJe.col(e).setConstant(detJ);
135 for (
auto g = 0; g < QuadratureRuleType::kPoints; ++g)
154template <
int QuadratureOrder, CMesh TMesh>
156 typename TMesh::ScalarType,
157 TMesh::ElementType::template QuadratureType<QuadratureOrder, typename TMesh::ScalarType>::
176template <CElement TElement,
class TDerivedEg,
class TDerivedX,
class TDerivedXi>
178 Eigen::DenseBase<TDerivedEg>
const& Eg,
179 Eigen::MatrixBase<TDerivedX>
const& X,
180 Eigen::MatrixBase<TDerivedXi>
const& Xi)
181 -> Eigen::Vector<typename TDerivedX::Scalar, Eigen::Dynamic>
183 PBAT_PROFILE_NAMED_SCOPE(
"pbat.fem.DeterminantOfJacobian");
184 using ScalarType =
typename TDerivedX::Scalar;
185 using ElementType = TElement;
186 using AffineElementType =
typename ElementType::AffineBaseType;
187 Eigen::Vector<ScalarType, Eigen::Dynamic> detJe(Eg.cols());
189 auto const nodes = Eg.col(g);
190 auto const vertices = nodes(ElementType::Vertices);
191 auto constexpr kRowsJ = TDerivedX::RowsAtCompileTime;
192 auto constexpr kColsJ = AffineElementType::kNodes;
193 Eigen::Matrix<ScalarType, kRowsJ, kColsJ>
const Ve = X(Eigen::placeholders::all, vertices);
214template <CElement TElement,
class TDerivedE,
class TDerivedX,
class TDerivedeg,
class TDerivedXi>
216 Eigen::DenseBase<TDerivedE>
const& E,
217 Eigen::MatrixBase<TDerivedX>
const& X,
218 Eigen::MatrixBase<TDerivedeg>
const& eg,
219 Eigen::MatrixBase<TDerivedXi>
const& Xi)
220 -> Eigen::Vector<typename TDerivedX::Scalar, Eigen::Dynamic>
223 E(Eigen::placeholders::all, eg.derived()),
261 Eigen::MatrixBase<TDerivedX>
const& X,
262 Eigen::MatrixBase<TDerivedx>
const& x,
263 int const maxIterations = 5,
264 TScalar
const eps = 1e-10) -> Eigen::Vector<TScalar, TElement::kDims>
266 using ScalarType = TScalar;
268 std::is_same_v<ScalarType, typename TDerivedX::Scalar>,
269 "X and x must have given scalar type");
271 std::is_same_v<ScalarType, typename TDerivedx::Scalar>,
272 "X and x must have given scalar type");
273 using ElementType = TElement;
274 assert(x.cols() == ElementType::kNodes);
275 auto constexpr kDims = ElementType::kDims;
276 auto constexpr kNodes = ElementType::kNodes;
277 auto constexpr kOutDims = Eigen::MatrixBase<TDerivedx>::RowsAtCompileTime;
279 auto const coords =
common::ToEigen(ElementType::Coordinates).reshaped(kDims, kNodes);
280 auto const vertexLagrangePositions =
281 (coords(Eigen::placeholders::all, ElementType::Vertices).template cast<ScalarType>() /
282 static_cast<ScalarType
>(ElementType::kOrder));
283 Eigen::Vector<ScalarType, kDims> Xik = vertexLagrangePositions.rowwise().sum() /
284 static_cast<ScalarType
>(ElementType::Vertices.size());
286 Eigen::Vector<ScalarType, kOutDims> rk = x * ElementType::N(Xik) - X;
287 Eigen::Matrix<ScalarType, kOutDims, kDims> J;
288 Eigen::LDLT<Eigen::Matrix<ScalarType, kDims, kDims>> LDLT;
291 if constexpr (ElementType::bHasConstantJacobian)
294 LDLT.compute(J.transpose() * J);
297 for (
auto k = 0; k < maxIterations; ++k)
299 if (rk.template lpNorm<1>() <= eps)
303 if constexpr (not ElementType::bHasConstantJacobian)
306 LDLT.compute(J.transpose() * J);
309 Xik -= LDLT.solve(J.transpose() * rk);
310 rk = x * ElementType::N(Xik) - X;
338 Eigen::DenseBase<TDerivedEg>
const& Eg,
339 Eigen::MatrixBase<TDerivedX>
const& X,
340 Eigen::MatrixBase<TDerivedXg>
const& Xg,
341 int maxIterations = 5,
342 TScalar eps = 1e-10) -> Eigen::Matrix<TScalar, TElement::kDims, Eigen::Dynamic>
344 PBAT_PROFILE_NAMED_SCOPE(
"pbat.fem.ReferencePositions");
346 std::is_same_v<TScalar, typename TDerivedX::Scalar>,
347 "X must have given scalar type");
349 std::is_same_v<TScalar, typename TDerivedXg::Scalar>,
350 "Xg must have given scalar type");
351 using ElementType = TElement;
352 using ScalarType = TScalar;
353 using MatrixType = Eigen::Matrix<ScalarType, ElementType::kDims, Eigen::Dynamic>;
354 MatrixType Xi(ElementType::kDims, Eg.cols());
356 auto const nodes = Eg.col(g);
357 auto constexpr kOutDims = TDerivedX::RowsAtCompileTime;
358 auto constexpr kNodes = ElementType::kNodes;
359 Eigen::Matrix<ScalarType, kOutDims, kNodes>
const Xe = X(Eigen::placeholders::all, nodes);
360 Eigen::Vector<ScalarType, kOutDims>
const Xk = Xg.col(g);
381template <CElement TElement,
class TDerivedE,
class TDerivedX,
class TDerivedEg,
class TDerivedXg>
383 Eigen::DenseBase<TDerivedE>
const& E,
384 Eigen::MatrixBase<TDerivedX>
const& X,
385 Eigen::DenseBase<TDerivedEg>
const& eg,
386 Eigen::MatrixBase<TDerivedXg>
const& Xg,
387 int maxIterations = 5,
388 typename TDerivedXg::Scalar eps = 1e-10)
389 -> Eigen::Matrix<typename TDerivedXg::Scalar, TElement::kDims, Eigen::Dynamic>
392 E(Eigen::placeholders::all, eg.derived()),
415template <CMesh TMesh,
class TDerivedEg,
class TDerivedXg>
418 Eigen::DenseBase<TDerivedEg>
const& eg,
419 Eigen::MatrixBase<TDerivedXg>
const& Xg,
420 int maxIterations = 5,
421 typename TMesh::ScalarType eps = 1e-10)
422 -> Eigen::Matrix<typename TMesh::ScalarType, TMesh::ElementType::kDims, Eigen::Dynamic>
425 mesh.E(Eigen::placeholders::all, eg.derived()),
Concepts for common types.
Eigen adaptors for ranges.
Concept for floating-point types.
Definition Concepts.h:56
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
auto Jacobian(Eigen::MatrixBase< TDerivedX > const &X, Eigen::MatrixBase< TDerivedx > const &x) -> Eigen::Matrix< TScalar, TDerivedx::RowsAtCompileTime, TElement::kDims >
Given a map , where is in reference space coordinates, computes .
Definition Jacobian.h:46
auto ReferencePosition(Eigen::MatrixBase< TDerivedX > const &X, Eigen::MatrixBase< TDerivedx > const &x, int const maxIterations=5, TScalar const eps=1e-10) -> Eigen::Vector< TScalar, TElement::kDims >
Computes the reference position such that . This inverse problem is solved using Gauss-Newton iterat...
Definition Jacobian.h:260
auto DeterminantOfJacobian(Eigen::MatrixBase< TDerived > const &J) -> typename TDerived::Scalar
Computes the determinant of a (potentially non-square) Jacobian matrix.
Definition Jacobian.h:68
auto DeterminantOfJacobianAt(Eigen::DenseBase< TDerivedEg > const &Eg, Eigen::MatrixBase< TDerivedX > const &X, Eigen::MatrixBase< TDerivedXi > const &Xi) -> Eigen::Vector< typename TDerivedX::Scalar, Eigen::Dynamic >
Computes the determinant of the Jacobian matrix at element quadrature points.
Definition Jacobian.h:177
auto ReferencePositions(Eigen::DenseBase< TDerivedEg > const &Eg, Eigen::MatrixBase< TDerivedX > const &X, Eigen::MatrixBase< TDerivedXg > const &Xg, int maxIterations=5, TScalar eps=1e-10) -> Eigen::Matrix< TScalar, TElement::kDims, Eigen::Dynamic >
Computes reference positions such that for every point in .
Definition Jacobian.h:337
std::ptrdiff_t Index
Index type.
Definition Aliases.h:17
Profiling utilities for the Physics-Based Animation Toolkit (PBAT)