OGS
VectorizedTensor.h
Go to the documentation of this file.
1
10#pragma once
11
12#include <Eigen/Core>
13#include <Eigen/LU>
14#include <type_traits>
15
16#include "BaseLib/Error.h"
17
18namespace MathLib
19{
22namespace VectorizedTensor
23{
25constexpr int size(int const displacement_dim)
26{
27 if (displacement_dim == 1)
28 {
29 return 3;
30 }
31 if (displacement_dim == 2)
32 {
33 return 5;
34 }
35 if (displacement_dim == 3)
36 {
37 return 9;
38 }
40 "Cannot convert displacement dimension {} to vectorized tensor size.",
41 displacement_dim);
42}
43
45template <typename VectorizedTensor>
46constexpr int dimension()
47{
48 static_assert(VectorizedTensor::ColsAtCompileTime == 1);
49 constexpr int rows = VectorizedTensor::RowsAtCompileTime;
50 if (rows == 3)
51 {
52 return 1;
53 }
54 if (rows == 5)
55 {
56 return 2;
57 }
58 if (rows == 9)
59 {
60 return 3;
61 }
63 "Cannot convert vectorized tensor of size {} to displacement "
64 "dimension.",
65 rows);
66}
67
71template <int DisplacementDim>
72using Type = Eigen::Matrix<double, size(DisplacementDim), 1, Eigen::ColMajor>;
73
76template <int DisplacementDim>
77constexpr auto identity()
78{
79 static_assert(
80 0 < DisplacementDim && DisplacementDim <= 3,
81 "Identity is implemented only for displacement dimension 1, 2, or 3.");
83 size(DisplacementDim), 1,
84 [](Eigen::Index const row, [[maybe_unused]] Eigen::Index const col)
85 {
86 assert(col == 0);
87 if constexpr (DisplacementDim == 1)
88 { // All entries are diagonal entries.
89 return 1;
90 }
91 if constexpr (DisplacementDim == 2)
92 {
93 if (row == 0 || row == 3 || row == 4)
94 {
95 return 1;
96 }
97 }
98 if constexpr (DisplacementDim == 3)
99 {
100 if (row == 0 || row == 4 || row == 8)
101 {
102 return 1;
103 }
104 }
105 return 0;
106 });
107}
108
110template <typename Derived>
111double determinant(Eigen::MatrixBase<Derived> const& tensor)
112{
113 constexpr int displacement_dim = dimension<Derived>();
114 static_assert(0 < displacement_dim && displacement_dim <= 3,
115 "Vectorized tensor determinant is implemented only for "
116 "displacement dimension 1, 2, or 3.");
117
118 if constexpr (displacement_dim == 1)
119 {
120 return tensor[0] * tensor[1] * tensor[2];
121 }
122 if constexpr (displacement_dim == 2)
123 {
124 Eigen::Map<Eigen::Matrix2d const> const top_left{
125 tensor.derived().data()};
126
127 return top_left.determinant() * tensor[4];
128 }
129 if constexpr (displacement_dim == 3)
130 {
131 return Eigen::Map<Eigen::Matrix3d const>(tensor.derived().data())
132 .determinant();
133 }
134}
135
137bool isTensorConvertibleTo1d(Eigen::Matrix3d const& tensor);
138
146bool isTensorConvertibleTo2d(Eigen::Matrix3d const& tensor);
147
151template <int DisplacementDim, typename Derived>
152Type<DisplacementDim> toVector(Eigen::MatrixBase<Derived> const& tensor)
153{
154 static_assert(0 < DisplacementDim && DisplacementDim <= 3,
155 "Conversion to displacement dimension other than 1, 2, or 3 "
156 "is not valid.");
157
158 constexpr int rows = Derived::RowsAtCompileTime;
159 constexpr int cols = Derived::ColsAtCompileTime;
160 static_assert(rows == 3 || rows == Eigen::Dynamic);
161 static_assert(cols == 3 || cols == Eigen::Dynamic);
162 if (tensor.rows() != 3 || tensor.cols() != 3)
163 {
164 OGS_FATAL(
165 "Incorrect tensor size, must be 3x3, but tensor is {:d}x{:d}.",
166 tensor.rows(), tensor.cols());
167 }
168
169 if constexpr (DisplacementDim == 1)
170 {
171 if (!isTensorConvertibleTo1d(tensor))
172 {
173 OGS_FATAL(
174 "Cannot convert a tensor with non-zero off-diagonal elements "
175 "to a 1d vectorized tensor representation.");
176 }
177 return tensor.diagonal();
178 }
179 if constexpr (DisplacementDim == 2)
180 {
181 if (!isTensorConvertibleTo2d(tensor))
182 {
183 OGS_FATAL(
184 "Cannot convert a tensor with non-zero elements at (0, 2), (1, "
185 "2), (2, 0), and (2, 1) positions to a 2d vectorized tensor "
186 "representation.");
187 }
188 Type<2> result;
189 result.template head<4>() =
190 tensor.template block<2, 2>(0, 0).reshaped();
191 result(4) = tensor(2, 2);
192 return result;
193 }
194 if constexpr (DisplacementDim == 3)
195 {
196 return tensor.reshaped();
197 }
198 OGS_FATAL(
199 "Not all cases handled in the VectorizedTensor::toVector() function.");
200}
201
203template <int DisplacementDim>
204Eigen::Matrix3d toTensor(Type<DisplacementDim> const& tensor)
205{
206 static_assert(
207 DisplacementDim == 1 || DisplacementDim == 2 || DisplacementDim == 3,
208 "Conversion from displacement dimension other than 1, 2, or 3 "
209 "is not valid.");
210
211 using Matrix = Eigen::Matrix3d;
212 if constexpr (DisplacementDim == 1)
213 {
214 return tensor.asDiagonal();
215 }
216 if constexpr (DisplacementDim == 2)
217 {
218 Matrix m = Matrix::Zero();
219 m.template block<2, 2>(0, 0) =
220 Eigen::Map<Eigen::Matrix<double, 2, 2> const>(tensor.data());
221 m(2, 2) = tensor(4);
222 return m;
223 }
224 if constexpr (DisplacementDim == 3)
225 {
226 return Eigen::Map<Matrix const>(tensor.data());
227 }
228}
229
230} // namespace VectorizedTensor
231} // namespace MathLib
#define OGS_FATAL(...)
Definition Error.h:26
constexpr int dimension()
Displacement dimension of a vectorized tensor.
bool isTensorConvertibleTo2d(Eigen::Matrix3d const &tensor)
double determinant(Eigen::MatrixBase< Derived > const &tensor)
Computes determinant of a vectorized tensor.
constexpr int size(int const displacement_dim)
Vectorized tensor size for given displacement dimension.
bool isTensorConvertibleTo1d(Eigen::Matrix3d const &tensor)
Only a diagonal tensor can be converted to a 1d vectorized tensor.
Eigen::Matrix< double, size(DisplacementDim), 1, Eigen::ColMajor > Type
Eigen::Matrix3d toTensor(Type< DisplacementDim > const &tensor)
Converts a vectorized tensor to a 3x3 matrix.
Type< DisplacementDim > toVector(Eigen::MatrixBase< Derived > const &tensor)