deal.II version GIT relicensing-2289-g1e5549a87a 2024-12-21 21:30:00+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
symmetric_tensor.h
Go to the documentation of this file.
1// ------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4// Copyright (C) 2005 - 2024 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Part of the source code is dual licensed under Apache-2.0 WITH
9// LLVM-exception OR LGPL-2.1-or-later. Detailed license information
10// governing the source code and code contributions can be found in
11// LICENSE.md and CONTRIBUTING.md at the top level directory of deal.II.
12//
13// ------------------------------------------------------------------------
14
15#ifndef dealii_symmetric_tensor_h
16#define dealii_symmetric_tensor_h
17
18
19#include <deal.II/base/config.h>
20
25#include <deal.II/base/tensor.h>
26
27#include <array>
28
30
31// Forward declaration
32#ifndef DOXYGEN
33template <int rank, int dim, typename Number = double>
34class SymmetricTensor;
35#endif
36
47template <int dim, typename Number = double>
51
80template <int dim, typename Number = double>
84
122template <int dim, typename Number = double>
126
127template <int dim, typename Number>
130
131template <int dim, typename Number>
134
144template <int dim2, typename Number>
145DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE Number
147
158template <int dim, typename Number>
159DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
162
176template <int dim, typename Number>
179
180
181
182namespace internal
183{
184 // Workaround: The following 4 overloads are necessary to be able to
185 // compile the library with Apple Clang 8 and older. We should remove
186 // these overloads again when we bump the minimal required version to
187 // something later than clang-3.6 / Apple Clang 6.3.
188 template <int rank, int dim, typename T, typename U>
189 struct ProductTypeImpl<SymmetricTensor<rank, dim, T>, std::complex<U>>
190 {
191 using type =
192 SymmetricTensor<rank,
193 dim,
194 std::complex<typename ProductType<T, U>::type>>;
195 };
196
197 template <int rank, int dim, typename T, typename U>
198 struct ProductTypeImpl<SymmetricTensor<rank, dim, std::complex<T>>,
199 std::complex<U>>
200 {
201 using type =
202 SymmetricTensor<rank,
203 dim,
204 std::complex<typename ProductType<T, U>::type>>;
205 };
206
207 template <typename T, int rank, int dim, typename U>
208 struct ProductTypeImpl<std::complex<T>, SymmetricTensor<rank, dim, U>>
209 {
210 using type =
211 SymmetricTensor<rank,
212 dim,
213 std::complex<typename ProductType<T, U>::type>>;
214 };
215
216 template <int rank, int dim, typename T, typename U>
217 struct ProductTypeImpl<std::complex<T>,
218 SymmetricTensor<rank, dim, std::complex<U>>>
219 {
220 using type =
221 SymmetricTensor<rank,
222 dim,
223 std::complex<typename ProductType<T, U>::type>>;
224 };
225 // end workaround
226
231 namespace SymmetricTensorImplementation
232 {
237 template <int rank, int dim, typename Number>
238 struct Inverse;
239 } // namespace SymmetricTensorImplementation
240
245 namespace SymmetricTensorAccessors
246 {
255 merge(const TableIndices<2> &previous_indices,
256 const unsigned int new_index,
257 const unsigned int position)
258 {
259 AssertIndexRange(position, 2);
260
261 if (position == 0)
262 return {new_index, numbers::invalid_unsigned_int};
263 else
264 return {previous_indices[0], new_index};
265 }
266
267
268
277 merge(const TableIndices<4> &previous_indices,
278 const unsigned int new_index,
279 const unsigned int position)
280 {
281 AssertIndexRange(position, 4);
282
283 switch (position)
284 {
285 case 0:
286 return {new_index,
290 case 1:
291 return {previous_indices[0],
292 new_index,
295 case 2:
296 return {previous_indices[0],
297 previous_indices[1],
298 new_index,
300 case 3:
301 return {previous_indices[0],
302 previous_indices[1],
303 previous_indices[2],
304 new_index};
305 default:
307 return {};
308 }
309 }
310
311
318 template <int rank1,
319 int rank2,
320 int dim,
321 typename Number,
322 typename OtherNumber = Number>
324 {
326 using type =
327 ::SymmetricTensor<rank1 + rank2 - 4, dim, value_type>;
328 };
329
330
337 template <int dim, typename Number, typename OtherNumber>
338 struct double_contraction_result<2, 2, dim, Number, OtherNumber>
339 {
341 };
342
343
344
357 template <int rank, int dim, typename Number>
359
363 template <int dim, typename Number>
364 struct StorageType<2, dim, Number>
365 {
370 static const unsigned int n_independent_components =
371 (dim * dim + dim) / 2;
372
377 };
378
379
380
384 template <int dim, typename Number>
385 struct StorageType<4, dim, Number>
386 {
392 static const unsigned int n_rank2_components = (dim * dim + dim) / 2;
393
397 static const unsigned int n_independent_components =
398 (n_rank2_components *
400
408 };
409
410
411
416 template <int rank, int dim, bool constness, typename Number>
418
425 template <int rank, int dim, typename Number>
426 struct AccessorTypes<rank, dim, true, Number>
427 {
428 using tensor_type = const ::SymmetricTensor<rank, dim, Number>;
429
430 using reference = const Number &;
431 };
432
439 template <int rank, int dim, typename Number>
440 struct AccessorTypes<rank, dim, false, Number>
441 {
443
444 using reference = Number &;
445 };
446
447
480 template <int rank, int dim, bool constness, int P, typename Number>
482 {
483 public:
487 using reference =
491
492 private:
514
519 constexpr DEAL_II_ALWAYS_INLINE
520 Accessor(const Accessor &) = default;
521
522 public:
527 constexpr Accessor<rank, dim, constness, P - 1, Number>
528 operator[](const unsigned int i);
529
534 constexpr Accessor<rank, dim, constness, P - 1, Number>
535 operator[](const unsigned int i) const;
536
537 private:
543
544 // Declare some other classes as friends. Make sure to work around bugs
545 // in some compilers:
546 template <int, int, typename>
547 friend class ::SymmetricTensor;
548 template <int, int, bool, int, typename>
549 friend class Accessor;
550 friend class ::SymmetricTensor<rank, dim, Number>;
551 friend class Accessor<rank, dim, constness, P + 1, Number>;
552 };
553
554
555
563 template <int rank, int dim, bool constness, typename Number>
564 class Accessor<rank, dim, constness, 1, Number>
565 {
566 public:
570 using reference =
574
575 private:
600
605 constexpr DEAL_II_ALWAYS_INLINE
606 Accessor(const Accessor &) = default;
607
608 public:
613 constexpr reference
614 operator[](const unsigned int);
615
620 constexpr reference
621 operator[](const unsigned int) const;
622
623 private:
629
630 // Declare some other classes as friends. Make sure to work around bugs
631 // in some compilers:
632 template <int, int, typename>
633 friend class ::SymmetricTensor;
634 template <int, int, bool, int, typename>
636 friend class ::SymmetricTensor<rank, dim, Number>;
637 friend class SymmetricTensorAccessors::
638 Accessor<rank, dim, constness, 2, Number>;
639 };
640 } // namespace SymmetricTensorAccessors
641} // namespace internal
642
643
644
717template <int rank_, int dim, typename Number>
719{
720public:
721 static_assert(rank_ % 2 == 0, "A SymmetricTensor must have even rank!");
722
731 static constexpr unsigned int dimension = dim;
732
736 static const unsigned int rank = rank_;
737
743 static constexpr unsigned int n_independent_components =
745 n_independent_components;
746
751 constexpr DEAL_II_ALWAYS_INLINE
752 SymmetricTensor() = default;
753
767 template <typename OtherNumber>
769
786 constexpr SymmetricTensor(const Number (&array)[n_independent_components]);
787
793 template <typename OtherNumber>
794 DEAL_II_HOST constexpr explicit SymmetricTensor(
796
803 template <typename OtherNumber>
804 DEAL_II_HOST constexpr SymmetricTensor &
806
814 constexpr SymmetricTensor &
815 operator=(const Number &d);
816
822 constexpr operator Tensor<rank_, dim, Number>() const;
823
828 constexpr bool
830
835 constexpr bool
837
841 template <typename OtherNumber>
842 DEAL_II_HOST constexpr SymmetricTensor &
844
848 template <typename OtherNumber>
849 DEAL_II_HOST constexpr SymmetricTensor &
851
856 template <typename OtherNumber>
857 DEAL_II_HOST constexpr SymmetricTensor &
858 operator*=(const OtherNumber &factor);
859
863 template <typename OtherNumber>
864 DEAL_II_HOST constexpr SymmetricTensor &
865 operator/=(const OtherNumber &factor);
866
871 constexpr SymmetricTensor
872 operator-() const;
873
926 template <typename OtherNumber>
927 DEAL_II_HOST DEAL_II_CONSTEXPR typename internal::SymmetricTensorAccessors::
928 double_contraction_result<rank_, 2, dim, Number, OtherNumber>::type
930
935 template <typename OtherNumber>
936 DEAL_II_HOST DEAL_II_CONSTEXPR typename internal::SymmetricTensorAccessors::
937 double_contraction_result<rank_, 4, dim, Number, OtherNumber>::type
939
944 constexpr Number &
946
951 constexpr const Number &
952 operator()(const TableIndices<rank_> &indices) const;
953
959 constexpr internal::SymmetricTensorAccessors::
960 Accessor<rank_, dim, true, rank_ - 1, Number>
961 operator[](const unsigned int row) const;
962
968 constexpr internal::SymmetricTensorAccessors::
969 Accessor<rank_, dim, false, rank_ - 1, Number>
970 operator[](const unsigned int row);
971
978 constexpr const Number &
979 operator[](const TableIndices<rank_> &indices) const;
980
987 constexpr Number &
989
997 constexpr const Number &
998 access_raw_entry(const unsigned int unrolled_index) const;
999
1007 constexpr Number &
1008 access_raw_entry(const unsigned int unrolled_index);
1009
1021 norm() const;
1022
1030 static DEAL_II_HOST constexpr unsigned int
1032
1038 static DEAL_II_HOST constexpr TableIndices<rank_>
1039 unrolled_to_component_indices(const unsigned int i);
1040
1054 constexpr void
1056
1061 static DEAL_II_HOST constexpr std::size_t
1063
1069 template <class Archive>
1070 void
1071 serialize(Archive &ar, const unsigned int version);
1072
1073private:
1079
1083 using base_tensor_type = typename base_tensor_descriptor::base_tensor_type;
1084
1089
1090#ifndef DOXYGEN
1091
1092 // Make all other symmetric tensors friends.
1093 template <int, int, typename>
1094 friend class SymmetricTensor;
1095
1096 // Make a few more functions friends.
1097 template <int dim2, typename Number2>
1098 friend DEAL_II_HOST constexpr Number2
1100
1101 template <int dim2, typename Number2>
1102 friend DEAL_II_HOST DEAL_II_CONSTEXPR Number2
1104
1105 template <int dim2, typename Number2>
1108
1109 template <int dim2, typename Number2>
1112
1113 template <int dim2, typename Number2>
1116
1117 template <int dim2, typename Number2>
1120
1121
1122 // Make a few helper classes friends as well.
1124 Inverse<2, dim, Number>;
1125
1127 Inverse<4, dim, Number>;
1128#endif
1129};
1130
1131
1132
1133// ------------------------- inline functions ------------------------
1134
1135#ifndef DOXYGEN
1136
1137// provide declarations for static members
1138template <int rank, int dim, typename Number>
1139const unsigned int SymmetricTensor<rank, dim, Number>::dimension;
1140
1141template <int rank_, int dim, typename Number>
1142constexpr unsigned int
1143 SymmetricTensor<rank_, dim, Number>::n_independent_components;
1144
1145namespace internal
1146{
1147 namespace SymmetricTensorAccessors
1148 {
1149 template <int rank_, int dim, bool constness, int P, typename Number>
1151 Accessor<rank_, dim, constness, P, Number>::Accessor(
1152 tensor_type &tensor,
1153 const TableIndices<rank_> &previous_indices)
1154 : tensor(tensor)
1155 , previous_indices(previous_indices)
1156 {}
1157
1158
1159
1160 template <int rank_, int dim, bool constness, int P, typename Number>
1161 DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
1162 Accessor<rank_, dim, constness, P - 1, Number>
1163 Accessor<rank_, dim, constness, P, Number>::operator[](
1164 const unsigned int i)
1165 {
1166 return Accessor<rank_, dim, constness, P - 1, Number>(
1167 tensor, merge(previous_indices, i, rank_ - P));
1168 }
1169
1170
1171
1172 template <int rank_, int dim, bool constness, int P, typename Number>
1174 Accessor<rank_, dim, constness, P - 1, Number>
1175 Accessor<rank_, dim, constness, P, Number>::operator[](
1176 const unsigned int i) const
1177 {
1178 return Accessor<rank_, dim, constness, P - 1, Number>(
1179 tensor, merge(previous_indices, i, rank_ - P));
1180 }
1181
1182
1183
1184 template <int rank_, int dim, bool constness, typename Number>
1186 Accessor<rank_, dim, constness, 1, Number>::Accessor(
1187 tensor_type &tensor,
1188 const TableIndices<rank_> &previous_indices)
1189 : tensor(tensor)
1190 , previous_indices(previous_indices)
1191 {}
1192
1193
1194
1195 template <int rank_, int dim, bool constness, typename Number>
1196 DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
1197 typename Accessor<rank_, dim, constness, 1, Number>::reference
1198 Accessor<rank_, dim, constness, 1, Number>::operator[](
1199 const unsigned int i)
1200 {
1201 return tensor(merge(previous_indices, i, rank_ - 1));
1202 }
1203
1204
1205 template <int rank_, int dim, bool constness, typename Number>
1207 typename Accessor<rank_, dim, constness, 1, Number>::reference
1208 Accessor<rank_, dim, constness, 1, Number>::operator[](
1209 const unsigned int i) const
1210 {
1211 return tensor(merge(previous_indices, i, rank_ - 1));
1212 }
1213 } // namespace SymmetricTensorAccessors
1214} // namespace internal
1215
1216
1217
1218template <int rank_, int dim, typename Number>
1219template <typename OtherNumber>
1223{
1224 static_assert(rank == 2, "This function is only implemented for rank==2");
1225 for (unsigned int d = 0; d < dim; ++d)
1226 for (unsigned int e = 0; e < d; ++e)
1227 Assert(t[d][e] == t[e][d],
1228 ExcMessage("The incoming Tensor must be exactly symmetric."));
1229
1230 for (unsigned int d = 0; d < dim; ++d)
1231 data[d] = t[d][d];
1232
1233 for (unsigned int d = 0, c = 0; d < dim; ++d)
1234 for (unsigned int e = d + 1; e < dim; ++e, ++c)
1235 data[dim + c] = t[d][e];
1236}
1237
1238
1239
1240template <int rank_, int dim, typename Number>
1241template <typename OtherNumber>
1245 : data(initializer.data)
1246{}
1247
1248
1249
1250template <int rank_, int dim, typename Number>
1251DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
1253 const Number (&array)[n_independent_components])
1254 : data(
1255 *reinterpret_cast<const typename base_tensor_type::array_type *>(array))
1256{
1257 // ensure that the reinterpret_cast above actually works
1258 Assert(sizeof(typename base_tensor_type::array_type) == sizeof(array),
1260}
1261
1262
1263
1264template <int rank_, int dim, typename Number>
1265template <typename OtherNumber>
1266DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
1270{
1271 data = t.data;
1272 return *this;
1273}
1274
1275
1276
1277template <int rank_, int dim, typename Number>
1278DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
1281{
1283 ExcMessage("Only assignment with zero is allowed"));
1284 (void)d;
1285
1287
1288 return *this;
1289}
1290
1291
1292namespace internal
1293{
1294 namespace SymmetricTensorImplementation
1295 {
1296 template <int dim, typename Number>
1297 constexpr inline DEAL_II_ALWAYS_INLINE ::Tensor<2, dim, Number>
1298 convert_to_tensor(const ::SymmetricTensor<2, dim, Number> &s)
1299 {
1301
1302 // diagonal entries are stored first
1303 for (unsigned int d = 0; d < dim; ++d)
1304 t[d][d] = s.access_raw_entry(d);
1305
1306 // off-diagonal entries come next, row by row
1307 for (unsigned int d = 0, c = 0; d < dim; ++d)
1308 for (unsigned int e = d + 1; e < dim; ++e, ++c)
1309 {
1310 t[d][e] = s.access_raw_entry(dim + c);
1311 t[e][d] = s.access_raw_entry(dim + c);
1312 }
1313 return t;
1314 }
1315
1316
1317 template <int dim, typename Number>
1318 constexpr ::Tensor<4, dim, Number>
1319 convert_to_tensor(const ::SymmetricTensor<4, dim, Number> &st)
1320 {
1321 // utilize the symmetry properties of SymmetricTensor<4,dim>
1322 // discussed in the class documentation to avoid accessing all
1323 // independent elements of the input tensor more than once
1325
1326 for (unsigned int i = 0; i < dim; ++i)
1327 for (unsigned int j = i; j < dim; ++j)
1328 for (unsigned int k = 0; k < dim; ++k)
1329 for (unsigned int l = k; l < dim; ++l)
1330 t[TableIndices<4>(i, j, k, l)] = t[TableIndices<4>(i, j, l, k)] =
1331 t[TableIndices<4>(j, i, k, l)] =
1332 t[TableIndices<4>(j, i, l, k)] =
1333 st[TableIndices<4>(i, j, k, l)];
1334
1335 return t;
1336 }
1337
1338
1339 template <typename Number>
1340 struct Inverse<2, 1, Number>
1341 {
1342 constexpr static inline DEAL_II_ALWAYS_INLINE
1343 ::SymmetricTensor<2, 1, Number>
1344 value(const ::SymmetricTensor<2, 1, Number> &t)
1345 {
1347
1348 tmp[0][0] = 1.0 / t[0][0];
1349
1350 return tmp;
1351 }
1352 };
1353
1354
1355 template <typename Number>
1356 struct Inverse<2, 2, Number>
1357 {
1358 constexpr static inline DEAL_II_ALWAYS_INLINE
1359 ::SymmetricTensor<2, 2, Number>
1360 value(const ::SymmetricTensor<2, 2, Number> &t)
1361 {
1363
1364 // Sympy result: ([
1365 // [ t11/(t00*t11 - t01**2), -t01/(t00*t11 - t01**2)],
1366 // [-t01/(t00*t11 - t01**2), t00/(t00*t11 - t01**2)] ])
1367 const TableIndices<2> idx_00(0, 0);
1368 const TableIndices<2> idx_01(0, 1);
1369 const TableIndices<2> idx_11(1, 1);
1370 const Number inv_det_t =
1371 1.0 / (t[idx_00] * t[idx_11] - t[idx_01] * t[idx_01]);
1372 tmp[idx_00] = t[idx_11];
1373 tmp[idx_01] = -t[idx_01];
1374 tmp[idx_11] = t[idx_00];
1375 tmp *= inv_det_t;
1376
1377 return tmp;
1378 }
1379 };
1380
1381
1382 template <typename Number>
1383 struct Inverse<2, 3, Number>
1384 {
1385 constexpr static ::SymmetricTensor<2, 3, Number>
1386 value(const ::SymmetricTensor<2, 3, Number> &t)
1387 {
1389
1390 // Sympy result: ([
1391 // [ (t11*t22 - t12**2)/(t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1392 // 2*t01*t02*t12 - t02**2*t11),
1393 // (-t01*t22 + t02*t12)/(t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1394 // 2*t01*t02*t12 - t02**2*t11),
1395 // (t01*t12 - t02*t11)/(t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1396 // 2*t01*t02*t12 - t02**2*t11)],
1397 // [ (-t01*t22 + t02*t12)/(t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1398 // 2*t01*t02*t12 - t02**2*t11),
1399 // (t00*t22 - t02**2)/(t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1400 // 2*t01*t02*t12 - t02**2*t11),
1401 // (t00*t12 - t01*t02)/(-t00*t11*t22 + t00*t12**2 + t01**2*t22 -
1402 // 2*t01*t02*t12 + t02**2*t11)],
1403 // [ (t01*t12 - t02*t11)/(t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1404 // 2*t01*t02*t12 - t02**2*t11),
1405 // (t00*t12 - t01*t02)/(-t00*t11*t22 + t00*t12**2 + t01**2*t22 -
1406 // 2*t01*t02*t12 + t02**2*t11),
1407 // (-t00*t11 + t01**2)/(-t00*t11*t22 + t00*t12**2 + t01**2*t22 -
1408 // 2*t01*t02*t12 + t02**2*t11)] ])
1409 //
1410 // =
1411 //
1412 // [ (t11*t22 - t12**2)/det_t,
1413 // (-t01*t22 + t02*t12)/det_t,
1414 // (t01*t12 - t02*t11)/det_t],
1415 // [ (-t01*t22 + t02*t12)/det_t,
1416 // (t00*t22 - t02**2)/det_t,
1417 // (-t00*t12 + t01*t02)/det_t],
1418 // [ (t01*t12 - t02*t11)/det_t,
1419 // (-t00*t12 + t01*t02)/det_t,
1420 // (t00*t11 - t01**2)/det_t] ])
1421 //
1422 // with det_t = (t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1423 // 2*t01*t02*t12 - t02**2*t11)
1424 const TableIndices<2> idx_00(0, 0);
1425 const TableIndices<2> idx_01(0, 1);
1426 const TableIndices<2> idx_02(0, 2);
1427 const TableIndices<2> idx_11(1, 1);
1428 const TableIndices<2> idx_12(1, 2);
1429 const TableIndices<2> idx_22(2, 2);
1430 const Number inv_det_t =
1431 1.0 / (t[idx_00] * t[idx_11] * t[idx_22] -
1432 t[idx_00] * t[idx_12] * t[idx_12] -
1433 t[idx_01] * t[idx_01] * t[idx_22] +
1434 2.0 * t[idx_01] * t[idx_02] * t[idx_12] -
1435 t[idx_02] * t[idx_02] * t[idx_11]);
1436 tmp[idx_00] = t[idx_11] * t[idx_22] - t[idx_12] * t[idx_12];
1437 tmp[idx_01] = -t[idx_01] * t[idx_22] + t[idx_02] * t[idx_12];
1438 tmp[idx_02] = t[idx_01] * t[idx_12] - t[idx_02] * t[idx_11];
1439 tmp[idx_11] = t[idx_00] * t[idx_22] - t[idx_02] * t[idx_02];
1440 tmp[idx_12] = -t[idx_00] * t[idx_12] + t[idx_01] * t[idx_02];
1441 tmp[idx_22] = t[idx_00] * t[idx_11] - t[idx_01] * t[idx_01];
1442 tmp *= inv_det_t;
1443
1444 return tmp;
1445 }
1446 };
1447
1448
1449 template <typename Number>
1450 struct Inverse<4, 1, Number>
1451 {
1452 constexpr static inline ::SymmetricTensor<4, 1, Number>
1453 value(const ::SymmetricTensor<4, 1, Number> &t)
1454 {
1456 tmp.data[0][0] = 1.0 / t.data[0][0];
1457 return tmp;
1458 }
1459 };
1460
1461
1462 template <typename Number>
1463 struct Inverse<4, 2, Number>
1464 {
1465 constexpr static inline ::SymmetricTensor<4, 2, Number>
1466 value(const ::SymmetricTensor<4, 2, Number> &t)
1467 {
1469
1470 // Inverting this tensor is a little more complicated than necessary,
1471 // since we store the data of 't' as a 3x3 matrix t.data, but the
1472 // product between a rank-4 and a rank-2 tensor is really not the
1473 // product between this matrix and the 3-vector of a rhs, but rather
1474 //
1475 // B.vec = t.data * mult * A.vec
1476 //
1477 // where mult is a 3x3 matrix with entries [[1,0,0],[0,1,0],[0,0,2]] to
1478 // capture the fact that we need to add up both the c_ij12*a_12 and the
1479 // c_ij21*a_21 terms.
1480 //
1481 // In addition, in this scheme, the identity tensor has the matrix
1482 // representation mult^-1.
1483 //
1484 // The inverse of 't' therefore has the matrix representation
1485 //
1486 // inv.data = mult^-1 * t.data^-1 * mult^-1
1487 //
1488 // in order to compute it, let's first compute the inverse of t.data and
1489 // put it into tmp.data; at the end of the function we then scale the
1490 // last row and column of the inverse by 1/2, corresponding to the left
1491 // and right multiplication with mult^-1.
1492 const Number t4 = t.data[0][0] * t.data[1][1],
1493 t6 = t.data[0][0] * t.data[1][2],
1494 t8 = t.data[0][1] * t.data[1][0],
1495 t00 = t.data[0][2] * t.data[1][0],
1496 t01 = t.data[0][1] * t.data[2][0],
1497 t04 = t.data[0][2] * t.data[2][0],
1498 t07 = 1.0 / (t4 * t.data[2][2] - t6 * t.data[2][1] -
1499 t8 * t.data[2][2] + t00 * t.data[2][1] +
1500 t01 * t.data[1][2] - t04 * t.data[1][1]);
1501 tmp.data[0][0] =
1502 (t.data[1][1] * t.data[2][2] - t.data[1][2] * t.data[2][1]) * t07;
1503 tmp.data[0][1] =
1504 -(t.data[0][1] * t.data[2][2] - t.data[0][2] * t.data[2][1]) * t07;
1505 tmp.data[0][2] =
1506 -(-t.data[0][1] * t.data[1][2] + t.data[0][2] * t.data[1][1]) * t07;
1507 tmp.data[1][0] =
1508 -(t.data[1][0] * t.data[2][2] - t.data[1][2] * t.data[2][0]) * t07;
1509 tmp.data[1][1] = (t.data[0][0] * t.data[2][2] - t04) * t07;
1510 tmp.data[1][2] = -(t6 - t00) * t07;
1511 tmp.data[2][0] =
1512 -(-t.data[1][0] * t.data[2][1] + t.data[1][1] * t.data[2][0]) * t07;
1513 tmp.data[2][1] = -(t.data[0][0] * t.data[2][1] - t01) * t07;
1514 tmp.data[2][2] = (t4 - t8) * t07;
1515
1516 // scale last row and column as mentioned
1517 // above
1518 tmp.data[2][0] /= 2;
1519 tmp.data[2][1] /= 2;
1520 tmp.data[0][2] /= 2;
1521 tmp.data[1][2] /= 2;
1522 tmp.data[2][2] /= 4;
1523
1524 return tmp;
1525 }
1526 };
1527
1528
1529 template <typename Number>
1530 struct Inverse<4, 3, Number>
1531 {
1532 static ::SymmetricTensor<4, 3, Number>
1533 value(const ::SymmetricTensor<4, 3, Number> &t)
1534 {
1536
1537 // This function follows the exact same scheme as the 2d case, except
1538 // that hardcoding the inverse of a 6x6 matrix is pretty wasteful.
1539 // Instead, we use the Gauss-Jordan algorithm implemented for
1540 // FullMatrix. For historical reasons the following code is copied from
1541 // there, with the tangential benefit that we do not need to copy the
1542 // tensor entries to and from the FullMatrix.
1543 const unsigned int N = 6;
1544
1545 // First get an estimate of the size of the elements of this matrix,
1546 // for later checks whether the pivot element is large enough, or
1547 // whether we have to fear that the matrix is not regular.
1548 Number diagonal_sum = internal::NumberType<Number>::value(0.0);
1549 for (unsigned int i = 0; i < N; ++i)
1550 diagonal_sum += numbers::NumberTraits<Number>::abs(tmp.data[i][i]);
1551 const Number typical_diagonal_element =
1552 diagonal_sum / static_cast<double>(N);
1553 (void)typical_diagonal_element;
1554
1555 unsigned int p[N];
1556 for (unsigned int i = 0; i < N; ++i)
1557 p[i] = i;
1558
1559 for (unsigned int j = 0; j < N; ++j)
1560 {
1561 // Pivot search: search that part of the line on and right of the
1562 // diagonal for the largest element.
1563 Number max = numbers::NumberTraits<Number>::abs(tmp.data[j][j]);
1564 unsigned int r = j;
1565 for (unsigned int i = j + 1; i < N; ++i)
1566 if (numbers::NumberTraits<Number>::abs(tmp.data[i][j]) > max)
1567 {
1569 r = i;
1570 }
1571
1572 // Check whether the pivot is too small
1573 Assert(max > 1.e-16 * typical_diagonal_element,
1574 ExcMessage("This tensor seems to be noninvertible"));
1575
1576 // Row interchange
1577 if (r > j)
1578 {
1579 for (unsigned int k = 0; k < N; ++k)
1580 std::swap(tmp.data[j][k], tmp.data[r][k]);
1581
1582 std::swap(p[j], p[r]);
1583 }
1584
1585 // Transformation
1586 const Number hr = 1. / tmp.data[j][j];
1587 tmp.data[j][j] = hr;
1588 for (unsigned int k = 0; k < N; ++k)
1589 {
1590 if (k == j)
1591 continue;
1592 for (unsigned int i = 0; i < N; ++i)
1593 {
1594 if (i == j)
1595 continue;
1596 tmp.data[i][k] -= tmp.data[i][j] * tmp.data[j][k] * hr;
1597 }
1598 }
1599 for (unsigned int i = 0; i < N; ++i)
1600 {
1601 tmp.data[i][j] *= hr;
1602 tmp.data[j][i] *= -hr;
1603 }
1604 tmp.data[j][j] = hr;
1605 }
1606
1607 // Column interchange
1608 Number hv[N];
1609 for (unsigned int i = 0; i < N; ++i)
1610 {
1611 for (unsigned int k = 0; k < N; ++k)
1612 hv[p[k]] = tmp.data[i][k];
1613 for (unsigned int k = 0; k < N; ++k)
1614 tmp.data[i][k] = hv[k];
1615 }
1616
1617 // Scale rows and columns. The mult matrix
1618 // here is diag[1, 1, 1, 1/2, 1/2, 1/2].
1619 for (unsigned int i = 3; i < 6; ++i)
1620 for (unsigned int j = 0; j < 3; ++j)
1621 tmp.data[i][j] /= 2;
1622
1623 for (unsigned int i = 0; i < 3; ++i)
1624 for (unsigned int j = 3; j < 6; ++j)
1625 tmp.data[i][j] /= 2;
1626
1627 for (unsigned int i = 3; i < 6; ++i)
1628 for (unsigned int j = 3; j < 6; ++j)
1629 tmp.data[i][j] /= 4;
1630
1631 return tmp;
1632 }
1633 };
1634
1635 } // namespace SymmetricTensorImplementation
1636} // namespace internal
1637
1638
1639
1640template <int rank_, int dim, typename Number>
1643 const
1644{
1645 return internal::SymmetricTensorImplementation::convert_to_tensor(*this);
1646}
1647
1648
1649
1650template <int rank_, int dim, typename Number>
1651DEAL_II_HOST constexpr bool
1654{
1655 return data == t.data;
1656}
1657
1658
1659
1660template <int rank_, int dim, typename Number>
1661DEAL_II_HOST constexpr bool
1664{
1665 return data != t.data;
1666}
1667
1668
1669
1670template <int rank_, int dim, typename Number>
1671template <typename OtherNumber>
1672DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
1676{
1677 data += t.data;
1678 return *this;
1679}
1680
1681
1682
1683template <int rank_, int dim, typename Number>
1684template <typename OtherNumber>
1685DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
1689{
1690 data -= t.data;
1691 return *this;
1692}
1693
1694
1695
1696template <int rank_, int dim, typename Number>
1697template <typename OtherNumber>
1698DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
1701{
1702 data *= d;
1703 return *this;
1704}
1705
1706
1707
1708template <int rank_, int dim, typename Number>
1709template <typename OtherNumber>
1710DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
1713{
1714 data /= d;
1715 return *this;
1716}
1717
1718
1719
1720template <int rank_, int dim, typename Number>
1721DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
1724{
1725 SymmetricTensor tmp = *this;
1726 tmp.data = -tmp.data;
1727 return tmp;
1728}
1729
1730
1731
1732template <int rank_, int dim, typename Number>
1733DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE void
1735{
1736 data.clear();
1737}
1738
1739
1740
1741template <int rank_, int dim, typename Number>
1742DEAL_II_HOST constexpr std::size_t
1744{
1745 // all memory consists of statically allocated memory of the current
1746 // object, no pointers
1748}
1749
1750
1751
1752namespace internal
1753{
1757 template <int dim, typename Number, typename OtherNumber = Number>
1759 typename SymmetricTensorAccessors::
1760 double_contraction_result<2, 2, dim, Number, OtherNumber>::type
1761 perform_double_contraction(
1762 const typename SymmetricTensorAccessors::StorageType<2, dim, Number>::
1763 base_tensor_type &data,
1764 const typename SymmetricTensorAccessors::
1765 StorageType<2, dim, OtherNumber>::base_tensor_type &sdata)
1766 {
1767 using result_type = typename SymmetricTensorAccessors::
1768 double_contraction_result<2, 2, dim, Number, OtherNumber>::type;
1769
1770 switch (dim)
1771 {
1772 case 1:
1773 return data[0] * sdata[0];
1774
1775 default:
1776 // Start with the non-diagonal part. These values appear
1777 // twice in the matrix, but are only stored once. So we can
1778 // get the double-contraction sum for these elements using
1779 // only one multiplication each, and at the end multiplying
1780 // things by 2.
1781 result_type sum = data[dim] * sdata[dim];
1782 for (unsigned int d = dim + 1; d < (dim * (dim + 1) / 2); ++d)
1783 sum += data[d] * sdata[d];
1784 sum += sum; // sum *= 2
1785
1786 // Now add the contributions from the diagonal
1787 for (unsigned int d = 0; d < dim; ++d)
1788 sum += data[d] * sdata[d];
1789 return sum;
1790 }
1791 }
1792
1793
1794
1799 template <int dim, typename Number, typename OtherNumber = Number>
1801 typename SymmetricTensorAccessors::
1802 double_contraction_result<4, 2, dim, Number, OtherNumber>::type
1803 perform_double_contraction(
1804 const typename SymmetricTensorAccessors::StorageType<4, dim, Number>::
1805 base_tensor_type &data,
1806 const typename SymmetricTensorAccessors::
1807 StorageType<2, dim, OtherNumber>::base_tensor_type &sdata)
1808 {
1809 using result_type = typename SymmetricTensorAccessors::
1810 double_contraction_result<4, 2, dim, Number, OtherNumber>::type;
1811 using value_type = typename SymmetricTensorAccessors::
1812 double_contraction_result<4, 2, dim, Number, OtherNumber>::value_type;
1813
1814 const unsigned int data_dim = SymmetricTensorAccessors::
1815 StorageType<2, dim, value_type>::n_independent_components;
1816 value_type tmp[data_dim]{};
1817 for (unsigned int i = 0; i < data_dim; ++i)
1818 tmp[i] =
1819 perform_double_contraction<dim, Number, OtherNumber>(data[i], sdata);
1820 return result_type(tmp);
1821 }
1822
1823
1824
1829 template <int dim, typename Number, typename OtherNumber = Number>
1831 typename SymmetricTensorAccessors::StorageType<
1832 2,
1833 dim,
1834 typename SymmetricTensorAccessors::
1835 double_contraction_result<2, 4, dim, Number, OtherNumber>::value_type>::
1836 base_tensor_type
1837 perform_double_contraction(
1838 const typename SymmetricTensorAccessors::StorageType<2, dim, Number>::
1839 base_tensor_type &data,
1840 const typename SymmetricTensorAccessors::
1841 StorageType<4, dim, OtherNumber>::base_tensor_type &sdata)
1842 {
1843 using value_type = typename SymmetricTensorAccessors::
1844 double_contraction_result<2, 4, dim, Number, OtherNumber>::value_type;
1845 using base_tensor_type = typename SymmetricTensorAccessors::
1846 StorageType<2, dim, value_type>::base_tensor_type;
1847
1848 base_tensor_type tmp;
1849 for (unsigned int i = 0; i < tmp.dimension; ++i)
1850 {
1851 // Start with the non-diagonal part. These values appear
1852 // twice in the matrix, but are only stored once. So we can
1853 // get the double-contraction sum for these elements using
1854 // only one multiplication each, and at the end multiplying
1855 // things by 2.
1856 value_type sum = data[dim] * sdata[dim][i];
1857 for (unsigned int d = dim + 1; d < (dim * (dim + 1) / 2); ++d)
1858 sum += data[d] * sdata[d][i];
1859 sum += sum; // sum *= 2
1860
1861 // Now add the contributions from the diagonal
1862 for (unsigned int d = 0; d < dim; ++d)
1863 sum += data[d] * sdata[d][i];
1864 tmp[i] = sum;
1865 }
1866 return tmp;
1867 }
1868
1869
1870
1874 template <int dim, typename Number, typename OtherNumber = Number>
1876 typename SymmetricTensorAccessors::StorageType<
1877 4,
1878 dim,
1879 typename SymmetricTensorAccessors::
1880 double_contraction_result<4, 4, dim, Number, OtherNumber>::value_type>::
1881 base_tensor_type
1882 perform_double_contraction(
1883 const typename SymmetricTensorAccessors::StorageType<4, dim, Number>::
1884 base_tensor_type &data,
1885 const typename SymmetricTensorAccessors::
1886 StorageType<4, dim, OtherNumber>::base_tensor_type &sdata)
1887 {
1888 using value_type = typename SymmetricTensorAccessors::
1889 double_contraction_result<4, 4, dim, Number, OtherNumber>::value_type;
1890 using base_tensor_type = typename SymmetricTensorAccessors::
1891 StorageType<4, dim, value_type>::base_tensor_type;
1892
1893 const unsigned int data_dim = SymmetricTensorAccessors::
1894 StorageType<2, dim, value_type>::n_independent_components;
1895 base_tensor_type tmp;
1896 for (unsigned int i = 0; i < data_dim; ++i)
1897 for (unsigned int j = 0; j < data_dim; ++j)
1898 {
1899 // Start with the non-diagonal part
1900 for (unsigned int d = dim; d < (dim * (dim + 1) / 2); ++d)
1901 tmp[i][j] += data[i][d] * sdata[d][j];
1902 tmp[i][j] += tmp[i][j]; // tmp[i][j] *= 2;
1903
1904 // Now add the contributions from the diagonal
1905 for (unsigned int d = 0; d < dim; ++d)
1906 tmp[i][j] += data[i][d] * sdata[d][j];
1907 }
1908 return tmp;
1909 }
1910
1911} // end of namespace internal
1912
1913
1914
1915template <int rank_, int dim, typename Number>
1916template <typename OtherNumber>
1918 typename internal::SymmetricTensorAccessors::
1919 double_contraction_result<rank_, 2, dim, Number, OtherNumber>::type
1922{
1923 // Dispatch to functions that know the types of the involved
1924 // arguments via overloads.
1925 return internal::perform_double_contraction<dim, Number, OtherNumber>(data,
1926 s.data);
1927}
1928
1929
1930
1931template <int rank_, int dim, typename Number>
1932template <typename OtherNumber>
1934 typename internal::SymmetricTensorAccessors::
1935 double_contraction_result<rank_, 4, dim, Number, OtherNumber>::type
1938{
1939 typename internal::SymmetricTensorAccessors::
1940 double_contraction_result<rank_, 4, dim, Number, OtherNumber>::type tmp;
1941 tmp.data =
1942 internal::perform_double_contraction<dim, Number, OtherNumber>(data,
1943 s.data);
1944 return tmp;
1945}
1946
1947
1948
1949// internal namespace to switch between the
1950// access of different tensors. There used to
1951// be explicit instantiations before for
1952// different ranks and dimensions, but since
1953// we now allow for templates on the data
1954// type, and since we cannot partially
1955// specialize the implementation, this got
1956// into a separate namespace
1957namespace internal
1958{
1959 namespace SymmetricTensorImplementation
1960 {
1961 // a function to do the unrolling from a set of indices to a
1962 // scalar index into the array in which we store the elements of
1963 // a symmetric tensor
1964 //
1965 // this function is for rank-2 tensors
1966 template <int dim>
1967 constexpr inline DEAL_II_ALWAYS_INLINE unsigned int
1969 {
1970 AssertIndexRange(indices[0], dim);
1971 AssertIndexRange(indices[1], dim);
1972
1973 switch (dim)
1974 {
1975 case 1:
1976 {
1977 return 0;
1978 }
1979 case 2:
1980 {
1981 constexpr ::ndarray<unsigned int, 2, 2> table = {
1982 {{{0, 2}}, {{2, 1}}}};
1983 return table[indices[0]][indices[1]];
1984 }
1985 case 3:
1986 {
1987 constexpr ::ndarray<unsigned int, 3, 3> table = {
1988 {{{0, 3, 4}}, {{3, 1, 5}}, {{4, 5, 2}}}};
1989 return table[indices[0]][indices[1]];
1990 }
1991 case 4:
1992 {
1993 constexpr ::ndarray<unsigned int, 4, 4> table = {
1994 {{{0, 4, 5, 6}},
1995 {{4, 1, 7, 8}},
1996 {{5, 7, 2, 9}},
1997 {{6, 8, 9, 3}}}};
1998 return table[indices[0]][indices[1]];
1999 }
2000 default:
2001 // for the remainder, manually figure out the numbering
2002 {
2003 if (indices[0] == indices[1])
2004 return indices[0];
2005
2006 const TableIndices<2> sorted_indices(
2007 std::min(indices[0], indices[1]),
2008 std::max(indices[0], indices[1]));
2009
2010 // Here (d, e) are the row and column of the symmetric matrix and
2011 // 'dim + c' is the index into the Tensor<1, dim> actually used
2012 // for storage.
2013 unsigned int c = 0;
2014 for (unsigned int d = 0; d < dim; ++d)
2015 for (unsigned int e = d + 1; e < dim; ++e, ++c)
2016 if ((sorted_indices[0] == d) && (sorted_indices[1] == e))
2017 return dim + c;
2018
2019 // should never get here:
2021 return 0;
2022 }
2023 }
2024 }
2025
2026 // a function to do the unrolling from a set of indices to a
2027 // scalar index into the array in which we store the elements of
2028 // a symmetric tensor
2029 //
2030 // this function is for tensors of ranks not already handled
2031 // above
2032 template <int dim, int rank_>
2033 constexpr inline unsigned int
2035 {
2036 (void)indices;
2039 }
2040 } // namespace SymmetricTensorImplementation
2041
2042 template <int dim, typename Number>
2043 constexpr inline DEAL_II_ALWAYS_INLINE Number &
2044 symmetric_tensor_access(const TableIndices<2> &indices,
2045 typename SymmetricTensorAccessors::
2046 StorageType<2, dim, Number>::base_tensor_type &data)
2047 {
2048 return data[SymmetricTensorImplementation::component_to_unrolled_index<dim>(
2049 indices)];
2050 }
2051
2052
2053
2054 template <int dim, typename Number>
2055 constexpr inline DEAL_II_ALWAYS_INLINE const Number &
2056 symmetric_tensor_access(const TableIndices<2> &indices,
2057 const typename SymmetricTensorAccessors::
2058 StorageType<2, dim, Number>::base_tensor_type &data)
2059 {
2060 return data[SymmetricTensorImplementation::component_to_unrolled_index<dim>(
2061 indices)];
2062 }
2063
2064
2065
2066 template <int dim, typename Number>
2067 constexpr inline Number &
2068 symmetric_tensor_access(const TableIndices<4> &indices,
2069 typename SymmetricTensorAccessors::
2070 StorageType<4, dim, Number>::base_tensor_type &data)
2071 {
2072 switch (dim)
2073 {
2074 case 1:
2075 return data[0][0];
2076
2077 case 2:
2078 // each entry of the tensor can be thought of as an entry in a
2079 // matrix that maps the rolled-out rank-2 tensors into rolled-out
2080 // rank-2 tensors. this is the format in which we store rank-4
2081 // tensors. determine which position the present entry is
2082 // stored in
2083 {
2084 constexpr std::size_t base_index[2][2] = {{0, 2}, {2, 1}};
2085 return data[base_index[indices[0]][indices[1]]]
2086 [base_index[indices[2]][indices[3]]];
2087 }
2088 case 3:
2089 // each entry of the tensor can be thought of as an entry in a
2090 // matrix that maps the rolled-out rank-2 tensors into rolled-out
2091 // rank-2 tensors. this is the format in which we store rank-4
2092 // tensors. determine which position the present entry is
2093 // stored in
2094 {
2095 constexpr std::size_t base_index[3][3] = {{0, 3, 4},
2096 {3, 1, 5},
2097 {4, 5, 2}};
2098 return data[base_index[indices[0]][indices[1]]]
2099 [base_index[indices[2]][indices[3]]];
2100 }
2101
2102 default:
2104 }
2105
2106 // The code should never reach here.
2107 // We cannot return a static variable, as this class must support number
2108 // types that require no instances of the number type to be in scope during
2109 // a reinitialization procedure (e.g. ADOL-C adtl::adouble).
2110 return data[0][0];
2111 }
2112
2113
2114 template <int dim, typename Number>
2115 constexpr inline DEAL_II_ALWAYS_INLINE const Number &
2116 symmetric_tensor_access(const TableIndices<4> &indices,
2117 const typename SymmetricTensorAccessors::
2118 StorageType<4, dim, Number>::base_tensor_type &data)
2119 {
2120 switch (dim)
2121 {
2122 case 1:
2123 return data[0][0];
2124
2125 case 2:
2126 // each entry of the tensor can be thought of as an entry in a
2127 // matrix that maps the rolled-out rank-2 tensors into rolled-out
2128 // rank-2 tensors. this is the format in which we store rank-4
2129 // tensors. determine which position the present entry is
2130 // stored in
2131 {
2132 constexpr std::size_t base_index[2][2] = {{0, 2}, {2, 1}};
2133 return data[base_index[indices[0]][indices[1]]]
2134 [base_index[indices[2]][indices[3]]];
2135 }
2136 case 3:
2137 // each entry of the tensor can be thought of as an entry in a
2138 // matrix that maps the rolled-out rank-2 tensors into rolled-out
2139 // rank-2 tensors. this is the format in which we store rank-4
2140 // tensors. determine which position the present entry is
2141 // stored in
2142 {
2143 constexpr std::size_t base_index[3][3] = {{0, 3, 4},
2144 {3, 1, 5},
2145 {4, 5, 2}};
2146 return data[base_index[indices[0]][indices[1]]]
2147 [base_index[indices[2]][indices[3]]];
2148 }
2149
2150 default:
2152 }
2153
2154 // The code should never reach here.
2155 // We cannot return a static variable, as this class must support number
2156 // types that require no instances of the number type to be in scope during
2157 // a reinitialization procedure (e.g. ADOL-C adtl::adouble).
2158 return data[0][0];
2159 }
2160
2161} // end of namespace internal
2162
2163
2164
2165template <int rank_, int dim, typename Number>
2166DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE Number &
2168 const TableIndices<rank_> &indices)
2169{
2170 for (unsigned int r = 0; r < rank; ++r)
2171 AssertIndexRange(indices[r], dimension);
2172 return internal::symmetric_tensor_access<dim, Number>(indices, data);
2173}
2174
2175
2176
2177template <int rank_, int dim, typename Number>
2178DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE const Number &
2180 const TableIndices<rank_> &indices) const
2181{
2182 for (unsigned int r = 0; r < rank; ++r)
2183 AssertIndexRange(indices[r], dimension);
2184 return internal::symmetric_tensor_access<dim, Number>(indices, data);
2185}
2186
2187
2188
2189namespace internal
2190{
2191 namespace SymmetricTensorImplementation
2192 {
2193 template <int rank_>
2194 constexpr TableIndices<rank_>
2195 get_partially_filled_indices(const unsigned int row,
2196 const std::integral_constant<int, 2> &)
2197 {
2199 }
2200
2201
2202 template <int rank_>
2203 constexpr TableIndices<rank_>
2204 get_partially_filled_indices(const unsigned int row,
2205 const std::integral_constant<int, 4> &)
2206 {
2207 return TableIndices<rank_>(row,
2211 }
2212 } // namespace SymmetricTensorImplementation
2213} // namespace internal
2214
2215
2216template <int rank_, int dim, typename Number>
2217DEAL_II_HOST constexpr DEAL_II_ALWAYS_INLINE internal::
2218 SymmetricTensorAccessors::Accessor<rank_, dim, true, rank_ - 1, Number>
2219 SymmetricTensor<rank_, dim, Number>::operator[](const unsigned int row) const
2220{
2221 return internal::SymmetricTensorAccessors::
2222 Accessor<rank_, dim, true, rank_ - 1, Number>(
2223 *this,
2224 internal::SymmetricTensorImplementation::get_partially_filled_indices<
2225 rank_>(row, std::integral_constant<int, rank_>()));
2226}
2227
2228
2229
2230template <int rank_, int dim, typename Number>
2231DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE internal::
2232 SymmetricTensorAccessors::Accessor<rank_, dim, false, rank_ - 1, Number>
2234{
2235 return internal::SymmetricTensorAccessors::
2236 Accessor<rank_, dim, false, rank_ - 1, Number>(
2237 *this,
2238 internal::SymmetricTensorImplementation::get_partially_filled_indices<
2239 rank_>(row, std::integral_constant<int, rank_>()));
2240}
2241
2242
2243
2244template <int rank_, int dim, typename Number>
2245DEAL_II_HOST constexpr DEAL_II_ALWAYS_INLINE const Number &
2247 const TableIndices<rank_> &indices) const
2248{
2249 return operator()(indices);
2250}
2251
2252
2253
2254template <int rank_, int dim, typename Number>
2255DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE Number &
2257 const TableIndices<rank_> &indices)
2258{
2259 return operator()(indices);
2260}
2261
2262
2263
2264template <int rank_, int dim, typename Number>
2265DEAL_II_HOST constexpr inline const Number &
2267 const unsigned int index) const
2268{
2269 AssertIndexRange(index, n_independent_components);
2270 if constexpr (rank == 2)
2271 return data[index];
2272 else
2273 return data[decltype(data)::unrolled_to_component_indices(index)];
2274}
2275
2276
2277
2278template <int rank_, int dim, typename Number>
2279DEAL_II_HOST constexpr inline Number &
2281{
2282 AssertIndexRange(index, n_independent_components);
2283 if constexpr (rank == 2)
2284 return data[index];
2285 else
2286 return data[decltype(data)::unrolled_to_component_indices(index)];
2287}
2288
2289
2290
2291namespace internal
2292{
2293 template <int dim, typename Number>
2294 constexpr inline typename numbers::NumberTraits<Number>::real_type
2295 compute_norm(const typename SymmetricTensorAccessors::
2296 StorageType<2, dim, Number>::base_tensor_type &data)
2297 {
2298 // Make things work with AD types
2299 using std::sqrt;
2300 switch (dim)
2301 {
2302 case 1:
2304
2305 case 2:
2309
2310 case 3:
2317
2318 default:
2319 {
2320 typename numbers::NumberTraits<Number>::real_type return_value =
2322
2323 for (unsigned int d = 0; d < dim; ++d)
2324 return_value +=
2326 for (unsigned int d = dim; d < (dim * dim + dim) / 2; ++d)
2327 return_value +=
2329
2330 return sqrt(return_value);
2331 }
2332 }
2333 }
2334
2335
2336
2337 template <int dim, typename Number>
2338 constexpr inline typename numbers::NumberTraits<Number>::real_type
2339 compute_norm(const typename SymmetricTensorAccessors::
2340 StorageType<4, dim, Number>::base_tensor_type &data)
2341 {
2342 // Make things work with AD types
2343 using std::sqrt;
2344 switch (dim)
2345 {
2346 case 1:
2348
2349 default:
2350 {
2351 typename numbers::NumberTraits<Number>::real_type return_value =
2353
2354 const unsigned int n_independent_components = data.dimension;
2355
2356 for (unsigned int i = 0; i < dim; ++i)
2357 for (unsigned int j = 0; j < dim; ++j)
2358 return_value +=
2360 for (unsigned int i = 0; i < dim; ++i)
2361 for (unsigned int j = dim; j < n_independent_components; ++j)
2362 return_value +=
2364 for (unsigned int i = dim; i < n_independent_components; ++i)
2365 for (unsigned int j = 0; j < dim; ++j)
2366 return_value +=
2368 for (unsigned int i = dim; i < n_independent_components; ++i)
2369 for (unsigned int j = dim; j < n_independent_components; ++j)
2370 return_value +=
2372
2373 return sqrt(return_value);
2374 }
2375 }
2376 }
2377
2378} // end of namespace internal
2379
2380
2381
2382template <int rank_, int dim, typename Number>
2385{
2386 return internal::compute_norm<dim, Number>(data);
2387}
2388
2389
2390
2391template <int rank_, int dim, typename Number>
2392DEAL_II_HOST constexpr unsigned int
2394 const TableIndices<rank_> &indices)
2395{
2396 return internal::SymmetricTensorImplementation::component_to_unrolled_index<
2397 dim>(indices);
2398}
2399
2400
2401
2402namespace internal
2403{
2404 namespace SymmetricTensorImplementation
2405 {
2406 // a function to do the inverse of the unrolling from a set of
2407 // indices to a scalar index into the array in which we store
2408 // the elements of a symmetric tensor. in other words, it goes
2409 // from the scalar index into the array to a set of indices of
2410 // the tensor
2411 //
2412 // this function is for rank-2 tensors
2413 template <int dim>
2414 constexpr inline DEAL_II_ALWAYS_INLINE TableIndices<2>
2415 unrolled_to_component_indices(const unsigned int i,
2416 const std::integral_constant<int, 2> &)
2417 {
2418 Assert(
2421 i,
2422 0,
2424 switch (dim)
2425 {
2426 case 1:
2427 {
2428 return {0, 0};
2429 }
2430
2431 case 2:
2432 {
2433 const TableIndices<2> table[3] = {TableIndices<2>(0, 0),
2434 TableIndices<2>(1, 1),
2435 TableIndices<2>(0, 1)};
2436 return table[i];
2437 }
2438
2439 case 3:
2440 {
2441 const TableIndices<2> table[6] = {TableIndices<2>(0, 0),
2442 TableIndices<2>(1, 1),
2443 TableIndices<2>(2, 2),
2444 TableIndices<2>(0, 1),
2445 TableIndices<2>(0, 2),
2446 TableIndices<2>(1, 2)};
2447 return table[i];
2448 }
2449
2450 default:
2451 if (i < dim)
2452 return {i, i};
2453
2454 for (unsigned int d = 0, c = dim; d < dim; ++d)
2455 for (unsigned int e = d + 1; e < dim; ++e, ++c)
2456 if (c == i)
2457 return {d, e};
2458
2459 // should never get here:
2461 return {0, 0};
2462 }
2463 }
2464
2465 // a function to do the inverse of the unrolling from a set of
2466 // indices to a scalar index into the array in which we store
2467 // the elements of a symmetric tensor. in other words, it goes
2468 // from the scalar index into the array to a set of indices of
2469 // the tensor
2470 //
2471 // this function is for tensors of a rank not already handled
2472 // above
2473 template <int dim, int rank_>
2474 constexpr inline std::enable_if_t<rank_ != 2, TableIndices<rank_>>
2475 unrolled_to_component_indices(const unsigned int i,
2476 const std::integral_constant<int, rank_> &)
2477 {
2478 (void)i;
2479 Assert(
2480 (i <
2482 ExcIndexRange(i,
2483 0,
2485 n_independent_components));
2487 return TableIndices<rank_>();
2488 }
2489
2490 } // namespace SymmetricTensorImplementation
2491} // namespace internal
2492
2493template <int rank_, int dim, typename Number>
2496 const unsigned int i)
2497{
2498 return internal::SymmetricTensorImplementation::unrolled_to_component_indices<
2499 dim>(i, std::integral_constant<int, rank_>());
2500}
2501
2502
2503
2504template <int rank_, int dim, typename Number>
2505template <class Archive>
2506inline void
2507SymmetricTensor<rank_, dim, Number>::serialize(Archive &ar, const unsigned int)
2508{
2509 ar &data;
2510}
2511
2512
2513#endif // DOXYGEN
2514
2515/* ----------------- Non-member functions operating on tensors. ------------ */
2516
2517
2530template <int rank_, int dim, typename Number, typename OtherNumber>
2531DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
2541
2542
2555template <int rank_, int dim, typename Number, typename OtherNumber>
2556DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
2566
2567
2575template <int rank_, int dim, typename Number, typename OtherNumber>
2580{
2581 return Tensor<rank_, dim, Number>(left) + right;
2582}
2583
2584
2592template <int rank_, int dim, typename Number, typename OtherNumber>
2597{
2598 return left + Tensor<rank_, dim, OtherNumber>(right);
2599}
2600
2601
2609template <int rank_, int dim, typename Number, typename OtherNumber>
2614{
2615 return Tensor<rank_, dim, Number>(left) - right;
2616}
2617
2618
2626template <int rank_, int dim, typename Number, typename OtherNumber>
2631{
2632 return left - Tensor<rank_, dim, OtherNumber>(right);
2633}
2634
2635
2636
2637template <int dim, typename Number>
2640{
2641 switch (dim)
2642 {
2643 case 1:
2644 return t.data[0];
2645 case 2:
2646 return (t.data[0] * t.data[1] - t.data[2] * t.data[2]);
2647 case 3:
2648 {
2649 // in analogy to general tensors, but
2650 // there's something to be simplified for
2651 // the present case
2652 const Number tmp = t.data[3] * t.data[4] * t.data[5];
2653 return (tmp + tmp + t.data[0] * t.data[1] * t.data[2] -
2654 t.data[0] * t.data[5] * t.data[5] -
2655 t.data[1] * t.data[4] * t.data[4] -
2656 t.data[2] * t.data[3] * t.data[3]);
2657 }
2658 default:
2661 }
2662}
2663
2664
2665
2677template <int dim, typename Number>
2683
2684
2685
2686template <int dim, typename Number>
2687DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE Number
2689{
2690 Number t = d.data[0];
2691 for (unsigned int i = 1; i < dim; ++i)
2692 t += d.data[i];
2693 return t;
2694}
2695
2696
2708template <int dim, typename Number>
2709DEAL_II_HOST constexpr Number
2711{
2712 return trace(t);
2713}
2714
2715
2727template <typename Number>
2728DEAL_II_HOST constexpr DEAL_II_ALWAYS_INLINE Number
2733
2734
2735
2754template <typename Number>
2755DEAL_II_HOST constexpr DEAL_II_ALWAYS_INLINE Number
2757{
2758 return t[0][0] * t[1][1] - t[0][1] * t[0][1];
2759}
2760
2761
2762
2771template <typename Number>
2772DEAL_II_HOST constexpr DEAL_II_ALWAYS_INLINE Number
2774{
2775 return (t[0][0] * t[1][1] + t[1][1] * t[2][2] + t[2][2] * t[0][0] -
2776 t[0][1] * t[0][1] - t[0][2] * t[0][2] - t[1][2] * t[1][2]);
2777}
2778
2779
2780
2788template <typename Number>
2789std::array<Number, 1>
2791
2792
2793
2816template <typename Number>
2817std::array<Number, 2>
2819
2820
2821
2844template <typename Number>
2845std::array<Number, 3>
2847
2848
2849
2850namespace internal
2851{
2852 namespace SymmetricTensorImplementation
2853 {
2865 template <int dim, typename Number>
2866 void
2867 tridiagonalize(const ::SymmetricTensor<2, dim, Number> &A,
2869 std::array<Number, dim> &d,
2870 std::array<Number, dim - 1> &e);
2871
2872
2873
2887 template <int dim, typename Number>
2888 std::array<std::pair<Number, Tensor<1, dim, Number>>, dim>
2889 ql_implicit_shifts(const ::SymmetricTensor<2, dim, Number> &A);
2890
2891
2892
2906 template <int dim, typename Number>
2907 std::array<std::pair<Number, Tensor<1, dim, Number>>, dim>
2909
2910
2911
2925 template <typename Number>
2926 std::array<std::pair<Number, Tensor<1, 2, Number>>, 2>
2927 hybrid(const ::SymmetricTensor<2, 2, Number> &A);
2928
2929
2930
2945 template <typename Number>
2946 std::array<std::pair<Number, Tensor<1, 3, Number>>, 3>
2947 hybrid(const ::SymmetricTensor<2, 3, Number> &A);
2948
2953 template <int dim, typename Number>
2955 {
2956 using EigValsVecs = std::pair<Number, Tensor<1, dim, Number>>;
2957 bool
2958 operator()(const EigValsVecs &lhs, const EigValsVecs &rhs)
2959 {
2960 return lhs.first > rhs.first;
2961 }
2962 };
2963
2964 } // namespace SymmetricTensorImplementation
2965
2966} // namespace internal
2967
2968
2969
2970// The line below is to ensure that doxygen puts the full description
2971// of this global enumeration into the documentation
2972// See https://stackoverflow.com/a/1717984
2984{
2994 hybrid,
3012 jacobi
3013};
3014
3015
3016
3027template <int dim, typename Number>
3028std::array<std::pair<Number, Tensor<1, dim, Number>>, dim>
3032
3033
3034
3043template <int rank_, int dim, typename Number>
3046{
3047 return t;
3048}
3049
3050
3051
3052template <int dim, typename Number>
3053DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
3056{
3058
3059 // subtract scaled trace from the diagonal
3060 const Number tr = trace(t) * internal::NumberType<Number>::value(1.0 / dim);
3061 for (unsigned int i = 0; i < dim; ++i)
3062 tmp.data[i] -= tr;
3063
3064 return tmp;
3065}
3066
3067
3068
3069template <int dim, typename Number>
3073{
3074 // create a default constructed matrix filled with
3075 // zeros, then set the diagonal elements to one
3077 switch (dim)
3078 {
3079 case 1:
3081 break;
3082 case 2:
3083 tmp.data[0] = tmp.data[1] = internal::NumberType<Number>::value(1.);
3084 break;
3085 case 3:
3086 tmp.data[0] = tmp.data[1] = tmp.data[2] =
3088 break;
3089 default:
3090 for (unsigned int d = 0; d < dim; ++d)
3092 }
3093 return tmp;
3094}
3095
3096
3097
3098template <int dim, typename Number>
3101{
3103
3104 // fill the elements treating the diagonal
3105 for (unsigned int i = 0; i < dim; ++i)
3106 for (unsigned int j = 0; j < dim; ++j)
3107 tmp.data[i][j] =
3108 internal::NumberType<Number>::value((i == j ? 1. : 0.) - 1. / dim);
3109
3110 // then fill the ones that copy over the
3111 // non-diagonal elements. note that during
3112 // the double-contraction, we handle the
3113 // off-diagonal elements twice, so simply
3114 // copying requires a weight of 1/2
3115 for (unsigned int i = dim;
3116 i < internal::SymmetricTensorAccessors::StorageType<4, dim, Number>::
3117 n_rank2_components;
3118 ++i)
3120
3121 return tmp;
3122}
3123
3124
3125
3126template <int dim, typename Number>
3130{
3132
3133 // fill the elements treating the diagonal
3134 for (unsigned int i = 0; i < dim; ++i)
3136
3137 // then fill the ones that copy over the
3138 // non-diagonal elements. note that during
3139 // the double-contraction, we handle the
3140 // off-diagonal elements twice, so simply
3141 // copying requires a weight of 1/2
3142 for (unsigned int i = dim;
3143 i < internal::SymmetricTensorAccessors::StorageType<4, dim, Number>::
3144 n_rank2_components;
3145 ++i)
3147
3148 return tmp;
3149}
3150
3151
3152
3162template <int dim, typename Number>
3169
3170
3171
3182template <int dim, typename Number>
3189
3190
3191
3213template <int dim, typename Number>
3217{
3219
3220 // fill only the elements really needed
3221 for (unsigned int i = 0; i < dim; ++i)
3222 for (unsigned int j = i; j < dim; ++j)
3223 for (unsigned int k = 0; k < dim; ++k)
3224 for (unsigned int l = k; l < dim; ++l)
3225 tmp[i][j][k][l] = t1[i][j] * t2[k][l];
3226
3227 return tmp;
3228}
3229
3255template <int dim, typename Number>
3256std::pair<SymmetricTensor<2, dim, Number>, SymmetricTensor<2, dim, Number>>
3258{
3259 Assert(dim <= 3, ExcNotImplemented());
3260
3261 const std::array<std::pair<Number, Tensor<1, dim, Number>>, dim>
3262 eigen_system = eigenvectors(original_tensor);
3263
3264 std::pair<SymmetricTensor<2, dim, Number>, SymmetricTensor<2, dim, Number>>
3265 positive_negative_tensors;
3266
3267 auto &[positive_part_tensor, negative_part_tensor] =
3268 positive_negative_tensors;
3269
3270 positive_part_tensor = 0;
3271 for (unsigned int i = 0; i < dim; ++i)
3272 if (eigen_system[i].first > 0)
3273 positive_part_tensor += eigen_system[i].first *
3274 symmetrize(outer_product(eigen_system[i].second,
3275 eigen_system[i].second));
3276
3277 negative_part_tensor = 0;
3278 for (unsigned int i = 0; i < dim; ++i)
3279 if (eigen_system[i].first < 0)
3280 negative_part_tensor += eigen_system[i].first *
3281 symmetrize(outer_product(eigen_system[i].second,
3282 eigen_system[i].second));
3283
3284 return positive_negative_tensors;
3285}
3286
3319template <int dim, typename Number>
3320std::tuple<SymmetricTensor<2, dim, Number>,
3325 const SymmetricTensor<2, dim, Number> &original_tensor)
3326{
3327 Assert(dim <= 3, ExcNotImplemented());
3328
3329 auto heaviside_function{[](const double x) {
3330 if (std::fabs(x) < 1.0e-16)
3331 return 0.5;
3332 if (x > 0)
3333 return 1.0;
3334 else
3335 return 0.0;
3336 }};
3337
3338 std::tuple<SymmetricTensor<2, dim, Number>,
3342 positive_negative_tensors_projectors;
3343
3344 auto &[positive_part_tensor,
3345 negative_part_tensor,
3346 positive_projector,
3347 negative_projector] = positive_negative_tensors_projectors;
3348
3349 const std::array<std::pair<Number, Tensor<1, dim, Number>>, dim>
3350 eigen_system = eigenvectors(original_tensor);
3351
3352 positive_part_tensor = 0;
3353 for (unsigned int i = 0; i < dim; ++i)
3354 if (eigen_system[i].first > 0)
3355 positive_part_tensor += eigen_system[i].first *
3356 symmetrize(outer_product(eigen_system[i].second,
3357 eigen_system[i].second));
3358
3359 negative_part_tensor = 0;
3360 for (unsigned int i = 0; i < dim; ++i)
3361 if (eigen_system[i].first < 0)
3362 negative_part_tensor += eigen_system[i].first *
3363 symmetrize(outer_product(eigen_system[i].second,
3364 eigen_system[i].second));
3365
3366 std::array<SymmetricTensor<2, dim, Number>, dim> M;
3367 for (unsigned int a = 0; a < dim; ++a)
3368 M[a] =
3369 symmetrize(outer_product(eigen_system[a].second, eigen_system[a].second));
3370
3371 std::array<SymmetricTensor<4, dim, Number>, dim> Q;
3372 for (unsigned int a = 0; a < dim; ++a)
3373 Q[a] = outer_product(M[a], M[a]);
3374
3375 std::array<std::array<SymmetricTensor<4, dim, Number>, dim>, dim> G;
3376 for (unsigned int a = 0; a < dim; ++a)
3377 for (unsigned int b = 0; b < dim; ++b)
3378 for (unsigned int i = 0; i < dim; ++i)
3379 for (unsigned int j = 0; j < dim; ++j)
3380 for (unsigned int k = 0; k < dim; ++k)
3381 for (unsigned int l = 0; l < dim; ++l)
3382 G[a][b][i][j][k][l] =
3383 M[a][i][k] * M[b][j][l] + M[a][i][l] * M[b][j][k];
3384
3385 // positive P
3386 positive_projector = 0;
3387 for (unsigned int a = 0; a < dim; ++a)
3388 {
3389 double lambda_a = eigen_system[a].first;
3390 positive_projector += heaviside_function(lambda_a) * Q[a];
3391 for (unsigned int b = 0; b < dim; ++b)
3392 {
3393 if (b != a)
3394 {
3395 double lambda_b = eigen_system[b].first;
3396
3397 double v_ab = 0.0;
3398 if (std::fabs(lambda_a - lambda_b) > 1.0e-12)
3399 v_ab = (std::fmax(lambda_a, 0.0) - std::fmax(lambda_b, 0.0)) /
3400 (lambda_a - lambda_b);
3401 else
3402 v_ab = 0.5 * (heaviside_function(lambda_a) +
3403 heaviside_function(lambda_b));
3404
3405 positive_projector += 0.5 * v_ab * 0.5 * (G[a][b] + G[b][a]);
3406 }
3407 }
3408 }
3409
3410 // negative P
3411 negative_projector = 0;
3412 for (unsigned int a = 0; a < dim; ++a)
3413 {
3414 double lambda_a = eigen_system[a].first;
3415 negative_projector += heaviside_function(-lambda_a) * Q[a];
3416 for (unsigned int b = 0; b < dim; ++b)
3417 {
3418 if (b != a)
3419 {
3420 double lambda_b = eigen_system[b].first;
3421
3422 double v_ab = 0.0;
3423 if (std::fabs(lambda_a - lambda_b) > 1.0e-12)
3424 v_ab = (std::fmin(lambda_a, 0.0) - std::fmin(lambda_b, 0.0)) /
3425 (lambda_a - lambda_b);
3426 else
3427 v_ab = 0.5 * (heaviside_function(-lambda_a) +
3428 heaviside_function(-lambda_b));
3429
3430 negative_projector += 0.5 * v_ab * 0.5 * (G[a][b] + G[b][a]);
3431 }
3432 }
3433 }
3434
3435 return positive_negative_tensors_projectors;
3436}
3437
3445template <int dim, typename Number>
3446DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
3449{
3451 for (unsigned int d = 0; d < dim; ++d)
3452 result[d][d] = t[d][d];
3453
3454 const Number half = internal::NumberType<Number>::value(0.5);
3455 for (unsigned int d = 0; d < dim; ++d)
3456 for (unsigned int e = d + 1; e < dim; ++e)
3457 result[d][e] = (t[d][e] + t[e][d]) * half;
3458 return result;
3459}
3460
3461
3462
3474template <int dim, typename Number>
3475DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
3477 symmetrize(const Tensor<4, dim, Number> &t, const bool major_symmetry)
3478{
3480
3481 const Number half = internal::NumberType<Number>::value(0.5);
3482
3483 // minor symmetry - A_{ijkl}=A_{jikl}=A_{ijlk}=A_{jilk}
3484 for (unsigned int i = 0; i < dim; ++i)
3485 for (unsigned int j = 0; j < dim; ++j)
3486 for (unsigned int k = 0; k < dim; ++k)
3487 for (unsigned int l = 0; l < dim; ++l)
3488 {
3489 if (i != j && k == l)
3490 {
3491 // A_{ijkk}=A_{jikk}
3492 result[i][j][k][k] = (t[i][j][k][k] + t[j][i][k][k]) * half;
3493 }
3494 else if (i == j && k != l)
3495 {
3496 // A_{iikl}=A_{iilk}
3497 result[i][i][k][l] = (t[i][i][k][l] + t[i][i][l][k]) * half;
3498 }
3499 else if (i != j && k != l)
3500 {
3501 // A_{ijkl}=A_{jilk}
3502 result[i][j][k][l] = (t[i][j][k][l] + t[j][i][k][l] +
3503 t[i][j][l][k] + t[j][i][l][k]) *
3504 half * half;
3505 }
3506 else
3507 {
3508 // A_{iijj} and A_{iiii} unchanged
3509 result[i][j][k][l] = t[i][j][k][l];
3510 }
3511 }
3512
3513 // in case major symmetry is also required
3514 if (major_symmetry)
3515 {
3516 // major symmetry - A_{ijkl}=A_{klij}
3517 for (unsigned int i = 0; i < dim; ++i)
3518 for (unsigned int j = i; j < dim; ++j)
3519 for (unsigned int k = 0; k < dim; ++k)
3520 for (unsigned int l = k; l < dim; ++l)
3521 result[i][j][k][l] = (t[i][j][k][l] + t[k][l][i][j]) * half;
3522 }
3523 return result;
3524}
3525
3526
3527
3535template <int rank_, int dim, typename Number>
3536DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
3538 operator*(const SymmetricTensor<rank_, dim, Number> &t, const Number &factor)
3539{
3541 tt *= factor;
3542 return tt;
3543}
3544
3545
3546
3554template <int rank_, int dim, typename Number>
3556operator*(const Number &factor, const SymmetricTensor<rank_, dim, Number> &t)
3557{
3558 // simply forward to the other operator
3559 return t * factor;
3560}
3561
3562
3563
3588template <int rank_, int dim, typename Number, typename OtherNumber>
3590 rank_,
3591 dim,
3592 typename ProductType<Number,
3593 typename EnableIfScalar<OtherNumber>::type>::type>
3595 const OtherNumber &factor)
3596{
3597 // form the product. we have to convert the two factors into the final
3598 // type via explicit casts because, for awkward reasons, the C++
3599 // standard committee saw it fit to not define an
3600 // operator*(float,std::complex<double>)
3601 // (as well as with switched arguments and double<->float).
3602 using product_type = typename ProductType<Number, OtherNumber>::type;
3605 return tt;
3606}
3607
3608
3609
3617template <int rank_, int dim, typename Number, typename OtherNumber>
3619 rank_,
3620 dim,
3621 typename ProductType<OtherNumber,
3622 typename EnableIfScalar<Number>::type>::type>
3623operator*(const Number &factor,
3625{
3626 // simply forward to the other operator with switched arguments
3627 return (t * factor);
3628}
3629
3630
3631
3637template <int rank_, int dim, typename Number, typename OtherNumber>
3638DEAL_II_HOST constexpr inline SymmetricTensor<
3639 rank_,
3640 dim,
3641 typename ProductType<Number,
3642 typename EnableIfScalar<OtherNumber>::type>::type>
3644 const OtherNumber &factor)
3645{
3646 using product_type = typename ProductType<Number, OtherNumber>::type;
3649 return tt;
3650}
3651
3652
3653
3660template <int rank_, int dim>
3662operator*(const SymmetricTensor<rank_, dim> &t, const double factor)
3663{
3665 tt *= factor;
3666 return tt;
3667}
3668
3669
3670
3677template <int rank_, int dim>
3679operator*(const double factor, const SymmetricTensor<rank_, dim> &t)
3680{
3682 tt *= factor;
3683 return tt;
3684}
3685
3686
3687
3693template <int rank_, int dim>
3695operator/(const SymmetricTensor<rank_, dim> &t, const double factor)
3696{
3698 tt /= factor;
3699 return tt;
3700}
3701
3711template <int dim, typename Number, typename OtherNumber>
3716{
3717 return (t1 * t2);
3718}
3719
3720
3733template <int dim, typename Number, typename OtherNumber>
3734DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
3738{
3740 typename ProductType<Number, OtherNumber>::type>::value(0.0);
3741 for (unsigned int i = 0; i < dim; ++i)
3742 for (unsigned int j = 0; j < dim; ++j)
3743 s += t1[i][j] * t2[i][j];
3744 return s;
3745}
3746
3747
3760template <int dim, typename Number, typename OtherNumber>
3765{
3766 return scalar_product(t2, t1);
3767}
3768
3769
3784template <typename Number, typename OtherNumber>
3785DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE void
3790{
3791 tmp[0][0] = t[0][0][0][0] * s[0][0];
3792}
3793
3794
3795
3810template <typename Number, typename OtherNumber>
3811DEAL_II_HOST constexpr inline void
3816{
3817 tmp[0][0] = t[0][0][0][0] * s[0][0];
3818}
3819
3820
3821
3836template <typename Number, typename OtherNumber>
3837DEAL_II_HOST constexpr inline void
3842{
3843 const unsigned int dim = 2;
3844
3845 for (unsigned int i = 0; i < dim; ++i)
3846 for (unsigned int j = i; j < dim; ++j)
3847 tmp[i][j] = t[i][j][0][0] * s[0][0] + t[i][j][1][1] * s[1][1] +
3848 2 * t[i][j][0][1] * s[0][1];
3849}
3850
3851
3852
3867template <typename Number, typename OtherNumber>
3868DEAL_II_HOST constexpr inline void
3873{
3874 const unsigned int dim = 2;
3875
3876 for (unsigned int i = 0; i < dim; ++i)
3877 for (unsigned int j = i; j < dim; ++j)
3878 tmp[i][j] = s[0][0] * t[0][0][i][j] * +s[1][1] * t[1][1][i][j] +
3879 2 * s[0][1] * t[0][1][i][j];
3880}
3881
3882
3883
3898template <typename Number, typename OtherNumber>
3899DEAL_II_HOST constexpr inline void
3904{
3905 const unsigned int dim = 3;
3906
3907 for (unsigned int i = 0; i < dim; ++i)
3908 for (unsigned int j = i; j < dim; ++j)
3909 tmp[i][j] = t[i][j][0][0] * s[0][0] + t[i][j][1][1] * s[1][1] +
3910 t[i][j][2][2] * s[2][2] + 2 * t[i][j][0][1] * s[0][1] +
3911 2 * t[i][j][0][2] * s[0][2] + 2 * t[i][j][1][2] * s[1][2];
3912}
3913
3914
3915
3930template <typename Number, typename OtherNumber>
3931DEAL_II_HOST constexpr inline void
3936{
3937 const unsigned int dim = 3;
3938
3939 for (unsigned int i = 0; i < dim; ++i)
3940 for (unsigned int j = i; j < dim; ++j)
3941 tmp[i][j] = s[0][0] * t[0][0][i][j] + s[1][1] * t[1][1][i][j] +
3942 s[2][2] * t[2][2][i][j] + 2 * s[0][1] * t[0][1][i][j] +
3943 2 * s[0][2] * t[0][2][i][j] + 2 * s[1][2] * t[1][2][i][j];
3944}
3945
3946
3947
3954template <int dim, typename Number, typename OtherNumber>
3955DEAL_II_HOST constexpr Tensor<1,
3956 dim,
3959 const Tensor<1, dim, OtherNumber> &src2)
3960{
3962 for (unsigned int i = 0; i < dim; ++i)
3963 {
3964 dest[i] = src1[i][0] * src2[0];
3965 for (unsigned int j = 1; j < dim; ++j)
3966 dest[i] += src1[i][j] * src2[j];
3967 }
3968 return dest;
3969}
3970
3971
3978template <int dim, typename Number, typename OtherNumber>
3979DEAL_II_HOST constexpr Tensor<1,
3980 dim,
3984{
3985 // this is easy for symmetric tensors:
3986 return src2 * src1;
3987}
3988
3989
3990
4010template <int rank_1,
4011 int rank_2,
4012 int dim,
4013 typename Number,
4014 typename OtherNumber>
4016 typename Tensor<rank_1 + rank_2 - 2,
4017 dim,
4018 typename ProductType<Number, OtherNumber>::type>::tensor_type
4024
4025
4026
4046template <int rank_1,
4047 int rank_2,
4048 int dim,
4049 typename Number,
4050 typename OtherNumber>
4052 typename Tensor<rank_1 + rank_2 - 2,
4053 dim,
4054 typename ProductType<Number, OtherNumber>::type>::tensor_type
4057{
4058 return Tensor<rank_1, dim, Number>(src1) * src2;
4059}
4060
4061
4062
4072template <int dim, typename Number>
4073inline std::ostream &
4074operator<<(std::ostream &out, const SymmetricTensor<2, dim, Number> &t)
4075{
4076 // make our lives a bit simpler by outputting
4077 // the tensor through the operator for the
4078 // general Tensor class
4080
4081 for (unsigned int i = 0; i < dim; ++i)
4082 for (unsigned int j = 0; j < dim; ++j)
4083 tt[i][j] = t[i][j];
4084
4085 return out << tt;
4086}
4087
4088
4089
4099template <int dim, typename Number>
4100inline std::ostream &
4101operator<<(std::ostream &out, const SymmetricTensor<4, dim, Number> &t)
4102{
4103 // make our lives a bit simpler by outputting
4104 // the tensor through the operator for the
4105 // general Tensor class
4107
4108 for (unsigned int i = 0; i < dim; ++i)
4109 for (unsigned int j = 0; j < dim; ++j)
4110 for (unsigned int k = 0; k < dim; ++k)
4111 for (unsigned int l = 0; l < dim; ++l)
4112 tt[i][j][k][l] = t[i][j][k][l];
4113
4114 return out << tt;
4115}
4116
4117
4119
4120#endif
DEAL_II_HOST constexpr SymmetricTensor< rank_, dim, Number > operator*(const SymmetricTensor< rank_, dim, Number > &t, const Number &factor)
DEAL_II_HOST constexpr Number determinant(const SymmetricTensor< 2, dim, Number > &)
DEAL_II_HOST constexpr SymmetricTensor< rank_, dim, Number > transpose(const SymmetricTensor< rank_, dim, Number > &t)
DEAL_II_HOST constexpr internal::SymmetricTensorAccessors::Accessor< rank_, dim, false, rank_ - 1, Number > operator[](const unsigned int row)
std::pair< SymmetricTensor< 2, dim, Number >, SymmetricTensor< 2, dim, Number > > positive_negative_split(const SymmetricTensor< 2, dim, Number > &original_tensor)
DEAL_II_HOST constexpr SymmetricTensor< rank_, dim, typename ProductType< Number, typename EnableIfScalar< OtherNumber >::type >::type > operator/(const SymmetricTensor< rank_, dim, Number > &t, const OtherNumber &factor)
DEAL_II_HOST constexpr SymmetricTensor< 2, dim, Number > symmetrize(const Tensor< 2, dim, Number > &t)
DEAL_II_HOST constexpr void double_contract(SymmetricTensor< 2, 2, typename ProductType< Number, OtherNumber >::type > &tmp, const SymmetricTensor< 4, 2, Number > &t, const SymmetricTensor< 2, 2, OtherNumber > &s)
static DEAL_II_HOST constexpr std::size_t memory_consumption()
DEAL_II_HOST constexpr SymmetricTensor & operator/=(const OtherNumber &factor)
DEAL_II_HOST constexpr Tensor< rank_1+rank_2-2, dim, typenameProductType< Number, OtherNumber >::type >::tensor_type operator*(const Tensor< rank_1, dim, Number > &src1, const SymmetricTensor< rank_2, dim, OtherNumber > &src2)
DEAL_II_HOST constexpr Number third_invariant(const SymmetricTensor< 2, dim, Number > &t)
DEAL_II_HOST constexpr Tensor< 1, dim, typename ProductType< Number, OtherNumber >::type > operator*(const SymmetricTensor< 2, dim, Number > &src1, const Tensor< 1, dim, OtherNumber > &src2)
DEAL_II_HOST constexpr SymmetricTensor< rank_, dim, typename ProductType< OtherNumber, typename EnableIfScalar< Number >::type >::type > operator*(const Number &factor, const SymmetricTensor< rank_, dim, OtherNumber > &t)
DEAL_II_HOST constexpr Number & operator[](const TableIndices< rank_ > &indices)
std::array< Number, 2 > eigenvalues(const SymmetricTensor< 2, 2, Number > &T)
DEAL_II_HOST constexpr SymmetricTensor< rank_, dim, typename ProductType< Number, OtherNumber >::type > operator-(const SymmetricTensor< rank_, dim, Number > &left, const SymmetricTensor< rank_, dim, OtherNumber > &right)
void serialize(Archive &ar, const unsigned int version)
DEAL_II_HOST constexpr Number first_invariant(const SymmetricTensor< 2, dim, Number > &t)
std::array< Number, 1 > eigenvalues(const SymmetricTensor< 2, 1, Number > &T)
std::tuple< SymmetricTensor< 2, dim, Number >, SymmetricTensor< 2, dim, Number >, SymmetricTensor< 4, dim, Number >, SymmetricTensor< 4, dim, Number > > positive_negative_projectors(const SymmetricTensor< 2, dim, Number > &original_tensor)
DEAL_II_HOST constexpr SymmetricTensor< rank_, dim, typename ProductType< Number, typename EnableIfScalar< OtherNumber >::type >::type > operator*(const SymmetricTensor< rank_, dim, Number > &t, const OtherNumber &factor)
DEAL_II_HOST constexpr const Number & operator()(const TableIndices< rank_ > &indices) const
std::array< std::pair< Number, Tensor< 1, dim, Number > >, dim > eigenvectors(const SymmetricTensor< 2, dim, Number > &T, const SymmetricTensorEigenvectorMethod method=SymmetricTensorEigenvectorMethod::ql_implicit_shifts)
typename base_tensor_descriptor::base_tensor_type base_tensor_type
DEAL_II_HOST constexpr SymmetricTensor(const SymmetricTensor< rank_, dim, OtherNumber > &initializer)
DEAL_II_HOST constexpr ProductType< Number, OtherNumber >::type scalar_product(const Tensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, OtherNumber > &t2)
DEAL_II_HOST constexpr SymmetricTensor< 4, dim, Number > outer_product(const SymmetricTensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, Number > &t2)
DEAL_II_HOST constexpr SymmetricTensor< rank_, dim > operator/(const SymmetricTensor< rank_, dim > &t, const double factor)
DEAL_II_HOST constexpr bool operator==(const SymmetricTensor &) const
DEAL_II_HOST constexpr SymmetricTensor< 2, dim, Number > invert(const SymmetricTensor< 2, dim, Number > &t)
DEAL_II_HOST constexpr const Number & access_raw_entry(const unsigned int unrolled_index) const
DEAL_II_HOST constexpr Number & operator()(const TableIndices< rank_ > &indices)
DEAL_II_HOST constexpr SymmetricTensor & operator*=(const OtherNumber &factor)
DEAL_II_HOST constexpr ProductType< Number, OtherNumber >::type scalar_product(const SymmetricTensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, OtherNumber > &t2)
DEAL_II_HOST constexpr SymmetricTensor(const Number(&array)[n_independent_components])
DEAL_II_HOST constexpr bool operator!=(const SymmetricTensor &) const
DEAL_II_HOST constexpr SymmetricTensor & operator=(const Number &d)
DEAL_II_HOST constexpr Tensor< rank_, dim, typename ProductType< Number, OtherNumber >::type > operator+(const SymmetricTensor< rank_, dim, Number > &left, const Tensor< rank_, dim, OtherNumber > &right)
DEAL_II_HOST constexpr SymmetricTensor operator-() const
DEAL_II_HOST constexpr ProductType< Number, OtherNumber >::type scalar_product(const SymmetricTensor< 2, dim, Number > &t1, const Tensor< 2, dim, OtherNumber > &t2)
base_tensor_type data
DEAL_II_HOST constexpr SymmetricTensor< rank_, dim, typename ProductType< Number, OtherNumber >::type > operator+(const SymmetricTensor< rank_, dim, Number > &left, const SymmetricTensor< rank_, dim, OtherNumber > &right)
DEAL_II_HOST constexpr Number & access_raw_entry(const unsigned int unrolled_index)
DEAL_II_HOST constexpr Tensor< 1, dim, typename ProductType< Number, OtherNumber >::type > operator*(const Tensor< 1, dim, Number > &src1, const SymmetricTensor< 2, dim, OtherNumber > &src2)
DEAL_II_HOST constexpr Number trace(const SymmetricTensor< 2, dim2, Number > &)
DEAL_II_HOST constexpr SymmetricTensor< rank_, dim > operator*(const SymmetricTensor< rank_, dim > &t, const double factor)
SymmetricTensor(const Tensor< 2, dim, OtherNumber > &t)
DEAL_II_HOST constexpr void double_contract(SymmetricTensor< 2, 1, typename ProductType< Number, OtherNumber >::type > &tmp, const SymmetricTensor< 2, 1, Number > &s, const SymmetricTensor< 4, 1, OtherNumber > &t)
DEAL_II_HOST constexpr Tensor< rank_1+rank_2-2, dim, typenameProductType< Number, OtherNumber >::type >::tensor_type operator*(const SymmetricTensor< rank_1, dim, Number > &src1, const Tensor< rank_2, dim, OtherNumber > &src2)
DEAL_II_HOST constexpr internal::SymmetricTensorAccessors::double_contraction_result< rank_, 2, dim, Number, OtherNumber >::type operator*(const SymmetricTensor< 2, dim, OtherNumber > &s) const
static DEAL_II_HOST constexpr unsigned int component_to_unrolled_index(const TableIndices< rank_ > &indices)
DEAL_II_HOST constexpr void double_contract(SymmetricTensor< 2, 3, typename ProductType< Number, OtherNumber >::type > &tmp, const SymmetricTensor< 4, 3, Number > &t, const SymmetricTensor< 2, 3, OtherNumber > &s)
DEAL_II_HOST constexpr Tensor< rank_, dim, typename ProductType< Number, OtherNumber >::type > operator+(const Tensor< rank_, dim, Number > &left, const SymmetricTensor< rank_, dim, OtherNumber > &right)
DEAL_II_HOST constexpr void double_contract(SymmetricTensor< 2, 1, typename ProductType< Number, OtherNumber >::type > &tmp, const SymmetricTensor< 4, 1, Number > &t, const SymmetricTensor< 2, 1, OtherNumber > &s)
static DEAL_II_HOST constexpr TableIndices< rank_ > unrolled_to_component_indices(const unsigned int i)
DEAL_II_HOST constexpr SymmetricTensor< 4, dim, Number > deviator_tensor()
DEAL_II_HOST constexpr SymmetricTensor & operator-=(const SymmetricTensor< rank_, dim, OtherNumber > &)
DEAL_II_HOST constexpr void double_contract(SymmetricTensor< 2, 3, typename ProductType< Number, OtherNumber >::type > &tmp, const SymmetricTensor< 2, 3, Number > &s, const SymmetricTensor< 4, 3, OtherNumber > &t)
DEAL_II_HOST constexpr void clear()
DEAL_II_HOST constexpr SymmetricTensor< 4, dim, Number > identity_tensor()
DEAL_II_HOST constexpr SymmetricTensor< 4, dim, Number > invert(const SymmetricTensor< 4, dim, Number > &t)
DEAL_II_HOST constexpr void double_contract(SymmetricTensor< 2, 2, typename ProductType< Number, OtherNumber >::type > &tmp, const SymmetricTensor< 2, 2, Number > &s, const SymmetricTensor< 4, 2, OtherNumber > &t)
DEAL_II_HOST constexpr Number second_invariant(const SymmetricTensor< 2, 2, Number > &t)
DEAL_II_HOST constexpr SymmetricTensor< rank_, dim, Number > operator*(const Number &factor, const SymmetricTensor< rank_, dim, Number > &t)
DEAL_II_HOST constexpr numbers::NumberTraits< Number >::real_type norm() const
DEAL_II_HOST constexpr internal::SymmetricTensorAccessors::double_contraction_result< rank_, 4, dim, Number, OtherNumber >::type operator*(const SymmetricTensor< 4, dim, OtherNumber > &s) const
DEAL_II_HOST constexpr SymmetricTensor & operator=(const SymmetricTensor< rank_, dim, OtherNumber > &rhs)
DEAL_II_HOST constexpr SymmetricTensor()=default
DEAL_II_HOST constexpr Number second_invariant(const SymmetricTensor< 2, 3, Number > &t)
DEAL_II_HOST constexpr Number second_invariant(const SymmetricTensor< 2, 1, Number > &)
DEAL_II_HOST constexpr SymmetricTensor< 4, dim, Number > symmetrize(const Tensor< 4, dim, Number > &t, const bool major_symmetry)
DEAL_II_HOST constexpr SymmetricTensor< 2, dim, Number > deviator(const SymmetricTensor< 2, dim, Number > &)
DEAL_II_HOST constexpr Tensor< rank_, dim, typename ProductType< Number, OtherNumber >::type > operator-(const SymmetricTensor< rank_, dim, Number > &left, const Tensor< rank_, dim, OtherNumber > &right)
DEAL_II_HOST constexpr SymmetricTensor & operator+=(const SymmetricTensor< rank_, dim, OtherNumber > &)
DEAL_II_HOST constexpr const Number & operator[](const TableIndices< rank_ > &indices) const
DEAL_II_HOST constexpr Tensor< rank_, dim, typename ProductType< Number, OtherNumber >::type > operator-(const Tensor< rank_, dim, Number > &left, const SymmetricTensor< rank_, dim, OtherNumber > &right)
DEAL_II_HOST constexpr SymmetricTensor< 2, dim, Number > unit_symmetric_tensor()
DEAL_II_HOST constexpr SymmetricTensor< rank_, dim > operator*(const double factor, const SymmetricTensor< rank_, dim > &t)
std::array< Number, 3 > eigenvalues(const SymmetricTensor< 2, 3, Number > &T)
DEAL_II_HOST constexpr internal::SymmetricTensorAccessors::Accessor< rank_, dim, true, rank_ - 1, Number > operator[](const unsigned int row) const
typename AccessorTypes< rank, dim, constness, Number >::reference reference
typename AccessorTypes< rank, dim, constness, Number >::tensor_type tensor_type
DEAL_II_HOST constexpr Accessor(tensor_type &tensor, const TableIndices< rank > &previous_indices)
DEAL_II_HOST constexpr reference operator[](const unsigned int)
DEAL_II_HOST constexpr reference operator[](const unsigned int) const
DEAL_II_HOST constexpr Accessor< rank, dim, constness, P - 1, Number > operator[](const unsigned int i) const
typename AccessorTypes< rank, dim, constness, Number >::tensor_type tensor_type
DEAL_II_HOST constexpr Accessor(tensor_type &tensor, const TableIndices< rank > &previous_indices)
DEAL_II_HOST constexpr Accessor< rank, dim, constness, P - 1, Number > operator[](const unsigned int i)
typename AccessorTypes< rank, dim, constness, Number >::reference reference
DEAL_II_HOST constexpr Accessor(const Accessor &)=default
#define DEAL_II_ALWAYS_INLINE
Definition config.h:109
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:498
#define DEAL_II_CONSTEXPR
Definition config.h:234
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:499
std::ostream & operator<<(std::ostream &out, const DerivativeForm< order, dim, spacedim, Number > &df)
Point< 2 > second
Definition grid_out.cc:4630
Point< 2 > first
Definition grid_out.cc:4629
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcIndexRange(std::size_t arg1, std::size_t arg2, std::size_t arg3)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define DEAL_II_ASSERT_UNREACHABLE()
#define DEAL_II_NOT_IMPLEMENTED()
std::vector< index_type > data
Definition mpi.cc:735
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
Tensor< 2, dim, Number > l(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
T sum(const T &t, const MPI_Comm mpi_communicator)
DEAL_II_HOST constexpr TableIndices< 2 > merge(const TableIndices< 2 > &previous_indices, const unsigned int new_index, const unsigned int position)
void tridiagonalize(const ::SymmetricTensor< 2, dim, Number > &A, ::Tensor< 2, dim, Number > &Q, std::array< Number, dim > &d, std::array< Number, dim - 1 > &e)
constexpr bool value_is_zero(const Number &value)
Definition numbers.h:910
static const unsigned int invalid_unsigned_int
Definition types.h:220
STL namespace.
::VectorizedArray< Number, width > min(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
#define DEAL_II_HOST
Definition numbers.h:40
typename internal::ProductTypeImpl< std::decay_t< T >, std::decay_t< U > >::type type
static constexpr const T & value(const T &t)
Definition numbers.h:697
typename ProductType< Number, OtherNumber >::type value_type
std::pair< Number, Tensor< 1, dim, Number > > EigValsVecs
bool operator()(const EigValsVecs &lhs, const EigValsVecs &rhs)
static real_type abs(const number &x)
Definition numbers.h:588
DEAL_II_HOST constexpr Number determinant(const SymmetricTensor< 2, dim, Number > &)
DEAL_II_HOST constexpr SymmetricTensor< 2, dim, Number > symmetrize(const Tensor< 2, dim, Number > &t)
DEAL_II_HOST constexpr SymmetricTensor< 2, dim, Number > invert(const SymmetricTensor< 2, dim, Number > &)
std::array< std::pair< Number, Tensor< 1, dim, Number > >, dim > eigenvectors(const SymmetricTensor< 2, dim, Number > &T, const SymmetricTensorEigenvectorMethod method=SymmetricTensorEigenvectorMethod::ql_implicit_shifts)
DEAL_II_HOST constexpr SymmetricTensor< 4, dim, Number > outer_product(const SymmetricTensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, Number > &t2)
DEAL_II_HOST constexpr Number trace(const SymmetricTensor< 2, dim2, Number > &)
DEAL_II_HOST constexpr SymmetricTensor< 4, dim, Number > deviator_tensor()
DEAL_II_HOST constexpr SymmetricTensor< 4, dim, Number > identity_tensor()
SymmetricTensorEigenvectorMethod
DEAL_II_HOST constexpr SymmetricTensor< 2, dim, Number > deviator(const SymmetricTensor< 2, dim, Number > &)
DEAL_II_HOST constexpr SymmetricTensor< 2, dim, Number > unit_symmetric_tensor()