version 0.4.1
tensorutils.hh
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2021-2024 The Ikarus Developers mueller@ibb.uni-stuttgart.de
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
9#pragma once
10
11#include <numeric>
12#include <ranges>
13#include <unsupported/Eigen/CXX11/Tensor>
14
15#include <dune/common/promotiontraits.hh>
16
18#include <ikarus/utils/math.hh>
19namespace Ikarus {
20
31template <typename Derived, typename T, auto rank>
32Eigen::Tensor<typename Derived::Scalar, rank> tensorView(const Eigen::EigenBase<Derived>& matrix,
33 const std::array<T, rank>& dims) {
34 return Eigen::TensorMap<const Eigen::TensorFixedSize<
35 const typename Derived::Scalar, Eigen::Sizes<Derived::RowsAtCompileTime, Derived::ColsAtCompileTime>>>(
36 matrix.derived().eval().data(), dims);
37}
38
47auto dyadic(const auto& A_ij, const auto& B_kl) {
48 Eigen::array<Eigen::IndexPair<long>, 0> empty_index_list = {};
49 return A_ij.contract(B_kl, empty_index_list).eval();
50}
51
59template <typename ScalarType = double, int dim = 3>
61 Eigen::TensorFixedSize<ScalarType, Eigen::Sizes<dim, dim, dim, dim>> idTensor;
62 for (int i = 0; i < dim; ++i)
63 for (int j = 0; j < dim; ++j)
64 for (int k = 0; k < dim; ++k)
65 for (int l = 0; l < dim; ++l)
66 idTensor(i, j, k, l) = 0.5 * ((i == k) * (j == l) + (i == l) * (j == k));
67 return idTensor;
68}
69
81template <typename ScalarType = double, int dim = 3>
82auto symmetricFourthOrder(const auto& A, const auto& B) {
83 Eigen::TensorFixedSize<ScalarType, Eigen::Sizes<dim, dim, dim, dim>> res;
84 for (int i = 0; i < dim; ++i)
85 for (int j = 0; j < dim; ++j)
86 for (int k = 0; k < dim; ++k)
87 for (int l = 0; l < dim; ++l)
88 res(i, j, k, l) = 0.5 * (A(i, k) * B(j, l) + A(i, l) * B(j, k));
89 return res;
90}
91
100template <typename ScalarType = double, int dim = 3>
102 Eigen::TensorFixedSize<ScalarType, Eigen::Sizes<dim, dim, dim, dim>> idTensor;
103 idTensor.setZero();
104 for (int i = 0; i < dim; ++i)
105 for (int k = 0; k < dim; ++k)
106 idTensor(i, i, k, k) = 1.0;
107 return idTensor;
108}
109
121template <typename AType, typename BType>
122auto fourthOrderIKJL(const Eigen::MatrixBase<AType>& A, const Eigen::MatrixBase<BType>& B) {
123 static_assert(AType::RowsAtCompileTime == BType::RowsAtCompileTime);
124 static_assert(AType::ColsAtCompileTime == BType::ColsAtCompileTime);
125 using ScalarResultType = typename Dune::PromotionTraits<typename AType::Scalar, typename BType::Scalar>::PromotedType;
126 constexpr int dim = AType::RowsAtCompileTime;
127 Eigen::TensorFixedSize<ScalarResultType, Eigen::Sizes<dim, dim, dim, dim>> res;
128 for (int i = 0; i < dim; ++i)
129 for (int j = 0; j < dim; ++j)
130 for (int k = 0; k < dim; ++k)
131 for (int l = 0; l < dim; ++l)
132 res(i, j, k, l) = A(i, k) * B(j, l);
133 return res;
134}
135
144template <typename ScalarType, long int dim>
145auto symTwoSlots(const Eigen::TensorFixedSize<ScalarType, Eigen::Sizes<dim, dim, dim, dim>>& t,
146 const std::array<size_t, 2>& slots) {
147 std::array<size_t, 4> shuffleSlot;
148 std::iota(shuffleSlot.begin(), shuffleSlot.end(), 0); // create 0,1,2,3 array
149 std::swap(shuffleSlot[slots[0]], shuffleSlot[slots[1]]); // swap the given slots
150 return (0.5 * (t + t.shuffle(shuffleSlot))).eval();
151}
152
166constexpr Eigen::Index toVoigt(Eigen::Index i, Eigen::Index j) noexcept {
167 if (i == j) // _00 -> 0, _11 -> 1, _22 -> 2
168 return i;
169 if ((i == 1 and j == 2) or (i == 2 and j == 1)) // _12 and _21 --> 3
170 return 3;
171 if ((i == 0 and j == 2) or (i == 2 and j == 0)) // _02 and _20 --> 4
172 return 4;
173 if ((i == 0 and j == 1) or (i == 1 and j == 0)) // _01 and _10 --> 5
174 return 5;
175 assert(i < 3 and j < 3 && "For Voigt notation the indices need to be 0,1 or 2.");
176 __builtin_unreachable();
177}
178
193template <typename ScalarType = double>
194Eigen::Matrix<ScalarType, 6, 6> toVoigt(const Eigen::TensorFixedSize<ScalarType, Eigen::Sizes<3, 3, 3, 3>>& ft) {
195 Eigen::Matrix<ScalarType, 6, 6> mat;
196 for (Eigen::Index i = 0; i < 3; ++i)
197 for (Eigen::Index j = 0; j < 3; ++j)
198 for (Eigen::Index k = 0; k < 3; ++k)
199 for (Eigen::Index l = 0; l < 3; ++l)
200 mat(toVoigt(i, j), toVoigt(k, l)) = ft(i, j, k, l);
201 return mat;
202}
203
223template <typename ST, int size, int Options, int maxSize>
224requires((size > 0 and size <= 3) or (maxSize > 0 and maxSize <= 3 and size == Eigen::Dynamic))
225auto toVoigt(const Eigen::Matrix<ST, size, size, Options, maxSize, maxSize>& E, bool isStrain = true) {
226 constexpr bool isFixedSized = (size != Eigen::Dynamic);
227 const ST possibleStrainFactor = isStrain ? 2.0 : 1.0;
228
229 const size_t inputSize = isFixedSized ? size : E.rows();
230 auto EVoigt = [&]() {
231 if constexpr (isFixedSized) {
232 Eigen::Vector<ST, (size * (size + 1)) / 2> EVoigt;
233 EVoigt.template head<size>() = E.diagonal();
234 return EVoigt;
235 } else {
236 Eigen::Matrix<ST, Eigen::Dynamic, 1, Options, 6, 1> EVoigt;
237 EVoigt.resize((inputSize * (inputSize + 1)) / 2);
238 EVoigt.template head(inputSize) = E.diagonal();
239 return EVoigt;
240 }
241 }();
242
243 if (inputSize == 2)
244 EVoigt(2) = E(0, 1) * possibleStrainFactor;
245 else if (inputSize == 3) {
246 EVoigt(inputSize) = E(1, 2) * possibleStrainFactor;
247 EVoigt(inputSize + 1) = E(0, 2) * possibleStrainFactor;
248 EVoigt(inputSize + 2) = E(0, 1) * possibleStrainFactor;
249 }
250 return EVoigt;
251}
252
268template <typename ST, int size, int Options, int maxSize>
269requires((size == 1 or size == 3 or size == 6) or
270 ((maxSize == 1 or maxSize == 3 or maxSize == 6) and size == Eigen::Dynamic))
271auto fromVoigt(const Eigen::Matrix<ST, size, 1, Options, maxSize, 1>& EVoigt, bool isStrain = true) {
272 constexpr bool isFixedSized = (size != Eigen::Dynamic);
273 const ST possibleStrainFactor = isStrain ? 0.5 : 1.0;
274
275 const size_t inputSize = isFixedSized ? size : EVoigt.size();
276 const size_t matrixSize =
277 isFixedSized ? (-1 + ct_sqrt(1 + 8 * size)) / 2 : (-1 + static_cast<int>(std::sqrt(1 + 8 * inputSize))) / 2;
278
279 auto E = [&]() {
280 if constexpr (isFixedSized) {
281 Eigen::Matrix<ST, matrixSize, matrixSize> E;
282 E.diagonal() = EVoigt.template head<matrixSize>();
283 return E;
284 } else {
285 Eigen::Matrix<ST, Eigen::Dynamic, Eigen::Dynamic, Options, 3, 3> E;
286 E.resize(matrixSize, matrixSize);
287 E.diagonal() = EVoigt.template head(matrixSize);
288 return E;
289 }
290 }();
291
292 if (matrixSize == 2) {
293 E(0, 1) = E(1, 0) = EVoigt(2) * possibleStrainFactor;
294 } else if (matrixSize == 3) {
295 E(2, 1) = E(1, 2) = EVoigt(matrixSize) * possibleStrainFactor;
296 E(2, 0) = E(0, 2) = EVoigt(matrixSize + 1) * possibleStrainFactor;
297 E(1, 0) = E(0, 1) = EVoigt(matrixSize + 2) * possibleStrainFactor;
298 }
299
300 return E;
301}
302
316constexpr std::array<size_t, 2> fromVoigt(size_t i) {
317 if (i < 3) // _00 -> 0, _11 -> 1, _22 -> 2
318 return {i, i};
319 else if (i == 3)
320 return {1, 2};
321 else if (i == 4)
322 return {0, 2};
323 else if (i == 5)
324 return {0, 1};
325 else {
326 assert(i < 6 && "For Voigt notation the indices need to be 0 and 5.");
327 __builtin_unreachable();
328 }
329}
330
342template <typename ScalarType>
343auto fromVoigt(const Eigen::Matrix<ScalarType, 6, 6>& CVoigt) {
344 Eigen::TensorFixedSize<ScalarType, Eigen::Sizes<3, 3, 3, 3>> C;
345 // size_t iR=0,jR=0;
346 for (size_t i = 0; i < 6; ++i) {
347 for (size_t j = 0; j < 6; ++j) {
348 auto firstIndices = fromVoigt(i);
349 auto secondIndices = fromVoigt(j);
350 C(firstIndices[0], firstIndices[1], secondIndices[0], secondIndices[1]) = CVoigt(i, j);
351 }
352 }
353 return C;
354}
355
366template <typename Geometry>
367Eigen::Matrix3d calcTransformationMatrix2D(const Geometry& geometry) {
368 const auto& referenceElement = Dune::ReferenceElements<double, 2>::general(geometry.type());
369 const auto quadPos0 = referenceElement.position(0, 0);
370
371 const auto jacobianinvT0 = toEigen(geometry.jacobianInverseTransposed(quadPos0));
372 const auto detJ0 = geometry.integrationElement(quadPos0);
373
374 auto jaco = (jacobianinvT0).inverse().eval();
375 auto J11 = jaco(0, 0);
376 auto J12 = jaco(0, 1);
377 auto J21 = jaco(1, 0);
378 auto J22 = jaco(1, 1);
379
380 Eigen::Matrix3d T0{
381 { J11 * J11, J12 * J12, J11 * J12},
382 { J21 * J21, J22 * J22, J21 * J22},
383 {2.0 * J11 * J21, 2.0 * J12 * J22, J21 * J12 + J11 * J22}
384 };
385
386 return T0.inverse() * detJ0;
387}
388
399template <typename Geometry>
400Eigen::Matrix<double, 6, 6> calcTransformationMatrix3D(const Geometry& geometry) {
401 const auto& referenceElement = Dune::ReferenceElements<double, 3>::general(geometry.type());
402 const auto quadPos0 = referenceElement.position(0, 0);
403
404 const auto jacobianinvT0 = toEigen(geometry.jacobianInverseTransposed(quadPos0));
405 const auto detJ0 = geometry.integrationElement(quadPos0);
406
407 auto jaco = (jacobianinvT0).inverse().eval();
408 auto J11 = jaco(0, 0);
409 auto J12 = jaco(0, 1);
410 auto J13 = jaco(0, 2);
411 auto J21 = jaco(1, 0);
412 auto J22 = jaco(1, 1);
413 auto J23 = jaco(1, 2);
414 auto J31 = jaco(2, 0);
415 auto J32 = jaco(2, 1);
416 auto J33 = jaco(2, 2);
417
418 // clang-format off
419 Eigen::Matrix<double, 6, 6> T0 {
420 {J11 * J11, J12 * J12, J13 * J13, J11 * J12, J11 * J13, J12 * J13},
421 {J21 * J21, J22 * J22, J23 * J23, J21 * J22, J21 * J23, J22 * J23},
422 {J31 * J31, J32 * J32, J33 * J33, J31 * J32, J31 * J33, J32 * J33},
423 {2.0 * J11 * J21, 2.0 * J12 * J22, 2.0 * J13 * J23, J11 * J22 + J21 * J12, J11 * J23 + J21 * J13, J12 * J23 + J22 * J13},
424 {2.0 * J11 * J31, 2.0 * J12 * J32, 2.0 * J13 * J33, J11 * J32 + J31 * J12, J11 * J33 + J31 * J13, J12 * J33 + J32 * J13},
425 {2.0 * J31 * J21, 2.0 * J32 * J22, 2.0 * J33 * J23, J31 * J22 + J21 * J32, J31 * J23 + J21 * J33, J32 * J23 + J22 * J33}
426 };
427 // clang-format on
428
429 return T0.inverse() * detJ0;
430}
431
432} // namespace Ikarus
Implementation of math related algorithms.
Several concepts.
auto symmetricIdentityFourthOrder()
Generates a symmetric identity fourth-order tensor.
Definition: tensorutils.hh:60
auto symmetricFourthOrder(const auto &A, const auto &B)
Generates a symmetric fourth-order tensor based on two second-order input tensors.
Definition: tensorutils.hh:82
constexpr Eigen::Index toVoigt(Eigen::Index i, Eigen::Index j) noexcept
Converts 2D indices to Voigt notation index.
Definition: tensorutils.hh:166
Eigen::Tensor< typename Derived::Scalar, rank > tensorView(const Eigen::EigenBase< Derived > &matrix, const std::array< T, rank > &dims)
View an Eigen matrix as an Eigen Tensor with specified dimensions.
Definition: tensorutils.hh:32
auto fourthOrderIKJL(const Eigen::MatrixBase< AType > &A, const Eigen::MatrixBase< BType > &B)
Computes the IKJL product of two matrices.
Definition: tensorutils.hh:122
auto dyadic(const auto &A_ij, const auto &B_kl)
Computes the dyadic product of two Eigen tensors.
Definition: tensorutils.hh:47
auto identityFourthOrder()
Generates an identity fourth-order tensor.
Definition: tensorutils.hh:101
auto fromVoigt(const Eigen::Matrix< ST, size, 1, Options, maxSize, 1 > &EVoigt, bool isStrain=true)
Converts a vector given in Voigt notation to a matrix.
Definition: tensorutils.hh:271
auto symTwoSlots(const Eigen::TensorFixedSize< ScalarType, Eigen::Sizes< dim, dim, dim, dim > > &t, const std::array< size_t, 2 > &slots)
Creates a symmetric fourth-order tensor in the two specified slots of the input tensor.
Definition: tensorutils.hh:145
Definition: assemblermanipulatorbuildingblocks.hh:22
Eigen::Matrix3d calcTransformationMatrix2D(const Geometry &geometry)
Calculates the 2D transformation matrix.
Definition: tensorutils.hh:367
Eigen::Matrix< double, 6, 6 > calcTransformationMatrix3D(const Geometry &geometry)
Calculates the 3D transformation matrix.
Definition: tensorutils.hh:400
constexpr T ct_sqrt(T x)
Compile-time square root for integer types.
Definition: math.hh:47
Definition: truncatedconjugategradient.hh:24
Definition: concepts.hh:30