deal.II version 9.7.0
\(\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 - 2025 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
26#include <deal.II/base/tensor.h>
27#include <deal.II/base/types.h>
28
29#include <array>
30
32
33// Forward declaration
34#ifndef DOXYGEN
35template <int rank, int dim, typename Number = double>
36class SymmetricTensor;
37#endif
38
49template <int dim, typename Number = double>
53
110template <int dim, typename Number = double>
114
152template <int dim, typename Number = double>
156
157template <int dim, typename Number>
160
161template <int dim, typename Number>
164
174template <int dim2, typename Number>
175DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE Number
177
216template <int dim, typename Number>
217DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
220
234template <int dim, typename Number>
237
238
239
240namespace internal
241{
242 // Workaround: The following 4 overloads are necessary to be able to
243 // compile the library with Apple Clang 8 and older. We should remove
244 // these overloads again when we bump the minimal required version to
245 // something later than clang-3.6 / Apple Clang 6.3.
246 template <int rank, int dim, typename T, typename U>
247 struct ProductTypeImpl<SymmetricTensor<rank, dim, T>, std::complex<U>>
248 {
249 using type =
250 SymmetricTensor<rank,
251 dim,
252 std::complex<typename ProductType<T, U>::type>>;
253 };
254
255 template <int rank, int dim, typename T, typename U>
256 struct ProductTypeImpl<SymmetricTensor<rank, dim, std::complex<T>>,
257 std::complex<U>>
258 {
259 using type =
260 SymmetricTensor<rank,
261 dim,
262 std::complex<typename ProductType<T, U>::type>>;
263 };
264
265 template <typename T, int rank, int dim, typename U>
266 struct ProductTypeImpl<std::complex<T>, SymmetricTensor<rank, dim, U>>
267 {
268 using type =
269 SymmetricTensor<rank,
270 dim,
271 std::complex<typename ProductType<T, U>::type>>;
272 };
273
274 template <int rank, int dim, typename T, typename U>
275 struct ProductTypeImpl<std::complex<T>,
276 SymmetricTensor<rank, dim, std::complex<U>>>
277 {
278 using type =
279 SymmetricTensor<rank,
280 dim,
281 std::complex<typename ProductType<T, U>::type>>;
282 };
283 // end workaround
284
290 {
295 template <int rank, int dim, typename Number>
296 struct Inverse;
297 } // namespace SymmetricTensorImplementation
298
304 {
313 merge(const TableIndices<2> &previous_indices,
314 const unsigned int new_index,
315 const unsigned int position)
316 {
317 AssertIndexRange(position, 2);
318
319 if (position == 0)
320 return {new_index, numbers::invalid_unsigned_int};
321 else
322 return {previous_indices[0], new_index};
323 }
324
325
326
335 merge(const TableIndices<4> &previous_indices,
336 const unsigned int new_index,
337 const unsigned int position)
338 {
339 AssertIndexRange(position, 4);
340
341 switch (position)
342 {
343 case 0:
344 return {new_index,
348 case 1:
349 return {previous_indices[0],
350 new_index,
353 case 2:
354 return {previous_indices[0],
355 previous_indices[1],
356 new_index,
358 case 3:
359 return {previous_indices[0],
360 previous_indices[1],
361 previous_indices[2],
362 new_index};
363 default:
365 return {};
366 }
367 }
368
369
376 template <int rank1,
377 int rank2,
378 int dim,
379 typename Number,
380 typename OtherNumber = Number>
382 {
384 using type =
385 ::SymmetricTensor<rank1 + rank2 - 4, dim, value_type>;
386 };
387
388
395 template <int dim, typename Number, typename OtherNumber>
396 struct double_contraction_result<2, 2, dim, Number, OtherNumber>
397 {
399 };
400
401
402
415 template <int rank, int dim, typename Number>
417
421 template <int dim, typename Number>
422 struct StorageType<2, dim, Number>
423 {
428 static const unsigned int n_independent_components =
429 (dim * dim + dim) / 2;
430
435 };
436
437
438
442 template <int dim, typename Number>
443 struct StorageType<4, dim, Number>
444 {
450 static const unsigned int n_rank2_components = (dim * dim + dim) / 2;
451
455 static const unsigned int n_independent_components =
458
466 };
467
468
469
474 template <int rank, int dim, bool constness, typename Number>
476
483 template <int rank, int dim, typename Number>
484 struct AccessorTypes<rank, dim, true, Number>
485 {
486 using tensor_type = const ::SymmetricTensor<rank, dim, Number>;
487
488 using reference = const Number &;
489 };
490
497 template <int rank, int dim, typename Number>
498 struct AccessorTypes<rank, dim, false, Number>
499 {
501
502 using reference = Number &;
503 };
504
505
538 template <int rank, int dim, bool constness, int P, typename Number>
540 {
541 public:
545 using reference =
549
550 private:
572
577 constexpr DEAL_II_ALWAYS_INLINE
578 Accessor(const Accessor &) = default;
579
580 public:
585 constexpr Accessor<rank, dim, constness, P - 1, Number>
586 operator[](const unsigned int i);
587
592 constexpr Accessor<rank, dim, constness, P - 1, Number>
593 operator[](const unsigned int i) const;
594
595 private:
601
602 // Declare some other classes as friends. Make sure to work around bugs
603 // in some compilers:
604 template <int, int, typename>
605 friend class ::SymmetricTensor;
606 template <int, int, bool, int, typename>
607 friend class Accessor;
608 friend class ::SymmetricTensor<rank, dim, Number>;
609 friend class Accessor<rank, dim, constness, P + 1, Number>;
610 };
611
612
613
621 template <int rank, int dim, bool constness, typename Number>
622 class Accessor<rank, dim, constness, 1, Number>
623 {
624 public:
628 using reference =
632
633 private:
658
663 constexpr DEAL_II_ALWAYS_INLINE
664 Accessor(const Accessor &) = default;
665
666 public:
671 constexpr reference
672 operator[](const unsigned int);
673
678 constexpr reference
679 operator[](const unsigned int) const;
680
681 private:
687
688 // Declare some other classes as friends. Make sure to work around bugs
689 // in some compilers:
690 template <int, int, typename>
691 friend class ::SymmetricTensor;
692 template <int, int, bool, int, typename>
694 friend class ::SymmetricTensor<rank, dim, Number>;
695 friend class SymmetricTensorAccessors::
696 Accessor<rank, dim, constness, 2, Number>;
697 };
698 } // namespace SymmetricTensorAccessors
699} // namespace internal
700
701
702
775template <int rank_, int dim, typename Number>
777{
778public:
779 static_assert(rank_ % 2 == 0, "A SymmetricTensor must have even rank!");
780
789 static constexpr unsigned int dimension = dim;
790
794 static const unsigned int rank = rank_;
795
801 static constexpr unsigned int n_independent_components =
803 n_independent_components;
804
809 constexpr DEAL_II_ALWAYS_INLINE
810 SymmetricTensor() = default;
811
825 template <typename OtherNumber>
827
844 constexpr SymmetricTensor(const Number (&array)[n_independent_components]);
845
851 template <typename OtherNumber>
852 DEAL_II_HOST constexpr explicit SymmetricTensor(
854
861 template <typename OtherNumber>
862 DEAL_II_HOST constexpr SymmetricTensor &
864
872 constexpr SymmetricTensor &
873 operator=(const Number &d);
874
880 constexpr operator Tensor<rank_, dim, Number>() const;
881
886 constexpr bool
888
893 constexpr bool
895
899 template <typename OtherNumber>
900 DEAL_II_HOST constexpr SymmetricTensor &
902
906 template <typename OtherNumber>
907 DEAL_II_HOST constexpr SymmetricTensor &
909
914 template <typename OtherNumber>
915 DEAL_II_HOST constexpr SymmetricTensor &
916 operator*=(const OtherNumber &factor);
917
921 template <typename OtherNumber>
922 DEAL_II_HOST constexpr SymmetricTensor &
923 operator/=(const OtherNumber &factor);
924
929 constexpr SymmetricTensor
930 operator-() const;
931
984 template <typename OtherNumber>
985 DEAL_II_HOST DEAL_II_CONSTEXPR typename internal::SymmetricTensorAccessors::
986 double_contraction_result<rank_, 2, dim, Number, OtherNumber>::type
988
993 template <typename OtherNumber>
994 DEAL_II_HOST DEAL_II_CONSTEXPR typename internal::SymmetricTensorAccessors::
995 double_contraction_result<rank_, 4, dim, Number, OtherNumber>::type
997
1002 constexpr Number &
1004
1009 constexpr const Number &
1010 operator()(const TableIndices<rank_> &indices) const;
1011
1017 constexpr internal::SymmetricTensorAccessors::
1018 Accessor<rank_, dim, true, rank_ - 1, Number>
1019 operator[](const unsigned int row) const;
1020
1026 constexpr internal::SymmetricTensorAccessors::
1027 Accessor<rank_, dim, false, rank_ - 1, Number>
1028 operator[](const unsigned int row);
1029
1036 constexpr const Number &
1037 operator[](const TableIndices<rank_> &indices) const;
1038
1045 constexpr Number &
1047
1055 constexpr const Number &
1056 access_raw_entry(const unsigned int unrolled_index) const;
1057
1065 constexpr Number &
1066 access_raw_entry(const unsigned int unrolled_index);
1067
1079 norm() const;
1080
1088 static DEAL_II_HOST constexpr unsigned int
1090
1096 static DEAL_II_HOST constexpr TableIndices<rank_>
1097 unrolled_to_component_indices(const unsigned int i);
1098
1112 constexpr void
1114
1119 static DEAL_II_HOST constexpr std::size_t
1121
1127 template <class Archive>
1128 void
1129 serialize(Archive &ar, const unsigned int version);
1130
1131private:
1137
1141 using base_tensor_type = typename base_tensor_descriptor::base_tensor_type;
1142
1147
1148#ifndef DOXYGEN
1149
1150 // Make all other symmetric tensors friends.
1151 template <int, int, typename>
1152 friend class SymmetricTensor;
1153
1154 // Make a few more functions friends.
1155 template <int dim2, typename Number2>
1156 friend DEAL_II_HOST constexpr Number2
1158
1159 template <int dim2, typename Number2>
1160 friend DEAL_II_HOST DEAL_II_CONSTEXPR Number2
1162
1163 template <int dim2, typename Number2>
1166
1167 template <int dim2, typename Number2>
1170
1171 template <int dim2, typename Number2>
1174
1175 template <int dim2, typename Number2>
1178
1179
1180 // Make a few helper classes friends as well.
1182 Inverse<2, dim, Number>;
1183
1185 Inverse<4, dim, Number>;
1186#endif
1187};
1188
1189
1190
1191// ------------------------- inline functions ------------------------
1192
1193#ifndef DOXYGEN
1194
1195// provide declarations for static members
1196template <int rank, int dim, typename Number>
1197const unsigned int SymmetricTensor<rank, dim, Number>::dimension;
1198
1199template <int rank_, int dim, typename Number>
1200constexpr unsigned int
1202
1203namespace internal
1204{
1205 namespace SymmetricTensorAccessors
1206 {
1207 template <int rank_, int dim, bool constness, int P, typename Number>
1209 Accessor<rank_, dim, constness, P, Number>::Accessor(
1210 tensor_type &tensor,
1211 const TableIndices<rank_> &previous_indices)
1212 : tensor(tensor)
1213 , previous_indices(previous_indices)
1214 {}
1215
1216
1217
1218 template <int rank_, int dim, bool constness, int P, typename Number>
1219 DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
1220 Accessor<rank_, dim, constness, P - 1, Number>
1221 Accessor<rank_, dim, constness, P, Number>::operator[](
1222 const unsigned int i)
1223 {
1224 return Accessor<rank_, dim, constness, P - 1, Number>(
1225 tensor, merge(previous_indices, i, rank_ - P));
1226 }
1227
1228
1229
1230 template <int rank_, int dim, bool constness, int P, typename Number>
1232 Accessor<rank_, dim, constness, P - 1, Number>
1233 Accessor<rank_, dim, constness, P, Number>::operator[](
1234 const unsigned int i) const
1235 {
1236 return Accessor<rank_, dim, constness, P - 1, Number>(
1237 tensor, merge(previous_indices, i, rank_ - P));
1238 }
1239
1240
1241
1242 template <int rank_, int dim, bool constness, typename Number>
1244 Accessor<rank_, dim, constness, 1, Number>::Accessor(
1245 tensor_type &tensor,
1246 const TableIndices<rank_> &previous_indices)
1247 : tensor(tensor)
1248 , previous_indices(previous_indices)
1249 {}
1250
1251
1252
1253 template <int rank_, int dim, bool constness, typename Number>
1254 DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
1255 typename Accessor<rank_, dim, constness, 1, Number>::reference
1256 Accessor<rank_, dim, constness, 1, Number>::operator[](
1257 const unsigned int i)
1258 {
1259 return tensor(merge(previous_indices, i, rank_ - 1));
1260 }
1261
1262
1263 template <int rank_, int dim, bool constness, typename Number>
1265 typename Accessor<rank_, dim, constness, 1, Number>::reference
1266 Accessor<rank_, dim, constness, 1, Number>::operator[](
1267 const unsigned int i) const
1268 {
1269 return tensor(merge(previous_indices, i, rank_ - 1));
1270 }
1271 } // namespace SymmetricTensorAccessors
1272} // namespace internal
1273
1274
1275
1276template <int rank_, int dim, typename Number>
1277template <typename OtherNumber>
1281{
1282 static_assert(rank == 2, "This function is only implemented for rank==2");
1283 for (unsigned int d = 0; d < dim; ++d)
1284 for (unsigned int e = 0; e < d; ++e)
1285 Assert(t[d][e] == t[e][d],
1286 ExcMessage("The incoming Tensor must be exactly symmetric."));
1287
1288 for (unsigned int d = 0; d < dim; ++d)
1289 data[d] = t[d][d];
1290
1291 for (unsigned int d = 0, c = 0; d < dim; ++d)
1292 for (unsigned int e = d + 1; e < dim; ++e, ++c)
1293 data[dim + c] = t[d][e];
1294}
1295
1296
1297
1298template <int rank_, int dim, typename Number>
1299template <typename OtherNumber>
1303 : data(initializer.data)
1304{}
1305
1306
1307
1308template <int rank_, int dim, typename Number>
1309DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
1311 const Number (&array)[n_independent_components])
1312 : data(
1313 *reinterpret_cast<const typename base_tensor_type::array_type *>(array))
1314{
1315 // ensure that the reinterpret_cast above actually works
1316 Assert(sizeof(typename base_tensor_type::array_type) == sizeof(array),
1318}
1319
1320
1321
1322template <int rank_, int dim, typename Number>
1323template <typename OtherNumber>
1324DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
1328{
1329 data = t.data;
1330 return *this;
1331}
1332
1333
1334
1335template <int rank_, int dim, typename Number>
1336DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
1339{
1341 ExcMessage("Only assignment with zero is allowed"));
1342 (void)d;
1343
1345
1346 return *this;
1347}
1348
1349
1350namespace internal
1351{
1353 {
1354 template <int dim, typename Number>
1355 constexpr inline DEAL_II_ALWAYS_INLINE ::Tensor<2, dim, Number>
1356 convert_to_tensor(const ::SymmetricTensor<2, dim, Number> &s)
1357 {
1358 ::Tensor<2, dim, Number> t;
1359
1360 // diagonal entries are stored first
1361 for (unsigned int d = 0; d < dim; ++d)
1362 t[d][d] = s.access_raw_entry(d);
1363
1364 // off-diagonal entries come next, row by row
1365 for (unsigned int d = 0, c = 0; d < dim; ++d)
1366 for (unsigned int e = d + 1; e < dim; ++e, ++c)
1367 {
1368 t[d][e] = s.access_raw_entry(dim + c);
1369 t[e][d] = s.access_raw_entry(dim + c);
1370 }
1371 return t;
1372 }
1373
1374
1375 template <int dim, typename Number>
1376 constexpr ::Tensor<4, dim, Number>
1377 convert_to_tensor(const ::SymmetricTensor<4, dim, Number> &st)
1378 {
1379 // utilize the symmetry properties of SymmetricTensor<4,dim>
1380 // discussed in the class documentation to avoid accessing all
1381 // independent elements of the input tensor more than once
1382 ::Tensor<4, dim, Number> t;
1383
1384 for (unsigned int i = 0; i < dim; ++i)
1385 for (unsigned int j = i; j < dim; ++j)
1386 for (unsigned int k = 0; k < dim; ++k)
1387 for (unsigned int l = k; l < dim; ++l)
1388 t[TableIndices<4>(i, j, k, l)] = t[TableIndices<4>(i, j, l, k)] =
1389 t[TableIndices<4>(j, i, k, l)] =
1390 t[TableIndices<4>(j, i, l, k)] =
1391 st[TableIndices<4>(i, j, k, l)];
1392
1393 return t;
1394 }
1395
1396
1397 template <typename Number>
1398 struct Inverse<2, 1, Number>
1399 {
1400 constexpr static inline DEAL_II_ALWAYS_INLINE
1401 ::SymmetricTensor<2, 1, Number>
1402 value(const ::SymmetricTensor<2, 1, Number> &t)
1403 {
1404 ::SymmetricTensor<2, 1, Number> tmp;
1405
1406 tmp[0][0] = 1.0 / t[0][0];
1407
1408 return tmp;
1409 }
1410 };
1411
1412
1413 template <typename Number>
1414 struct Inverse<2, 2, Number>
1415 {
1416 constexpr static inline DEAL_II_ALWAYS_INLINE
1417 ::SymmetricTensor<2, 2, Number>
1418 value(const ::SymmetricTensor<2, 2, Number> &t)
1419 {
1420 ::SymmetricTensor<2, 2, Number> tmp;
1421
1422 // Sympy result: ([
1423 // [ t11/(t00*t11 - t01**2), -t01/(t00*t11 - t01**2)],
1424 // [-t01/(t00*t11 - t01**2), t00/(t00*t11 - t01**2)] ])
1425 const TableIndices<2> idx_00(0, 0);
1426 const TableIndices<2> idx_01(0, 1);
1427 const TableIndices<2> idx_11(1, 1);
1428 const Number inv_det_t =
1429 1.0 / (t[idx_00] * t[idx_11] - t[idx_01] * t[idx_01]);
1430 tmp[idx_00] = t[idx_11];
1431 tmp[idx_01] = -t[idx_01];
1432 tmp[idx_11] = t[idx_00];
1433 tmp *= inv_det_t;
1434
1435 return tmp;
1436 }
1437 };
1438
1439
1440 template <typename Number>
1441 struct Inverse<2, 3, Number>
1442 {
1443 constexpr static ::SymmetricTensor<2, 3, Number>
1444 value(const ::SymmetricTensor<2, 3, Number> &t)
1445 {
1446 ::SymmetricTensor<2, 3, Number> tmp;
1447
1448 // Sympy result: ([
1449 // [ (t11*t22 - t12**2)/(t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1450 // 2*t01*t02*t12 - t02**2*t11),
1451 // (-t01*t22 + t02*t12)/(t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1452 // 2*t01*t02*t12 - t02**2*t11),
1453 // (t01*t12 - t02*t11)/(t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1454 // 2*t01*t02*t12 - t02**2*t11)],
1455 // [ (-t01*t22 + t02*t12)/(t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1456 // 2*t01*t02*t12 - t02**2*t11),
1457 // (t00*t22 - t02**2)/(t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1458 // 2*t01*t02*t12 - t02**2*t11),
1459 // (t00*t12 - t01*t02)/(-t00*t11*t22 + t00*t12**2 + t01**2*t22 -
1460 // 2*t01*t02*t12 + t02**2*t11)],
1461 // [ (t01*t12 - t02*t11)/(t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1462 // 2*t01*t02*t12 - t02**2*t11),
1463 // (t00*t12 - t01*t02)/(-t00*t11*t22 + t00*t12**2 + t01**2*t22 -
1464 // 2*t01*t02*t12 + t02**2*t11),
1465 // (-t00*t11 + t01**2)/(-t00*t11*t22 + t00*t12**2 + t01**2*t22 -
1466 // 2*t01*t02*t12 + t02**2*t11)] ])
1467 //
1468 // =
1469 //
1470 // [ (t11*t22 - t12**2)/det_t,
1471 // (-t01*t22 + t02*t12)/det_t,
1472 // (t01*t12 - t02*t11)/det_t],
1473 // [ (-t01*t22 + t02*t12)/det_t,
1474 // (t00*t22 - t02**2)/det_t,
1475 // (-t00*t12 + t01*t02)/det_t],
1476 // [ (t01*t12 - t02*t11)/det_t,
1477 // (-t00*t12 + t01*t02)/det_t,
1478 // (t00*t11 - t01**2)/det_t] ])
1479 //
1480 // with det_t = (t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1481 // 2*t01*t02*t12 - t02**2*t11)
1482 const TableIndices<2> idx_00(0, 0);
1483 const TableIndices<2> idx_01(0, 1);
1484 const TableIndices<2> idx_02(0, 2);
1485 const TableIndices<2> idx_11(1, 1);
1486 const TableIndices<2> idx_12(1, 2);
1487 const TableIndices<2> idx_22(2, 2);
1488 const Number inv_det_t =
1489 1.0 / (t[idx_00] * t[idx_11] * t[idx_22] -
1490 t[idx_00] * t[idx_12] * t[idx_12] -
1491 t[idx_01] * t[idx_01] * t[idx_22] +
1492 2.0 * t[idx_01] * t[idx_02] * t[idx_12] -
1493 t[idx_02] * t[idx_02] * t[idx_11]);
1494 tmp[idx_00] = t[idx_11] * t[idx_22] - t[idx_12] * t[idx_12];
1495 tmp[idx_01] = -t[idx_01] * t[idx_22] + t[idx_02] * t[idx_12];
1496 tmp[idx_02] = t[idx_01] * t[idx_12] - t[idx_02] * t[idx_11];
1497 tmp[idx_11] = t[idx_00] * t[idx_22] - t[idx_02] * t[idx_02];
1498 tmp[idx_12] = -t[idx_00] * t[idx_12] + t[idx_01] * t[idx_02];
1499 tmp[idx_22] = t[idx_00] * t[idx_11] - t[idx_01] * t[idx_01];
1500 tmp *= inv_det_t;
1501
1502 return tmp;
1503 }
1504 };
1505
1506
1507 template <typename Number>
1508 struct Inverse<4, 1, Number>
1509 {
1510 constexpr static inline ::SymmetricTensor<4, 1, Number>
1511 value(const ::SymmetricTensor<4, 1, Number> &t)
1512 {
1513 ::SymmetricTensor<4, 1, Number> tmp;
1514 tmp.data[0][0] = 1.0 / t.data[0][0];
1515 return tmp;
1516 }
1517 };
1518
1519
1520 template <typename Number>
1521 struct Inverse<4, 2, Number>
1522 {
1523 constexpr static inline ::SymmetricTensor<4, 2, Number>
1524 value(const ::SymmetricTensor<4, 2, Number> &t)
1525 {
1526 ::SymmetricTensor<4, 2, Number> tmp;
1527
1528 // Inverting this tensor is a little more complicated than necessary,
1529 // since we store the data of 't' as a 3x3 matrix t.data, but the
1530 // product between a rank-4 and a rank-2 tensor is really not the
1531 // product between this matrix and the 3-vector of a rhs, but rather
1532 //
1533 // B.vec = t.data * mult * A.vec
1534 //
1535 // where mult is a 3x3 matrix with entries [[1,0,0],[0,1,0],[0,0,2]] to
1536 // capture the fact that we need to add up both the c_ij12*a_12 and the
1537 // c_ij21*a_21 terms.
1538 //
1539 // In addition, in this scheme, the identity tensor has the matrix
1540 // representation mult^-1.
1541 //
1542 // The inverse of 't' therefore has the matrix representation
1543 //
1544 // inv.data = mult^-1 * t.data^-1 * mult^-1
1545 //
1546 // in order to compute it, let's first compute the inverse of t.data and
1547 // put it into tmp.data; at the end of the function we then scale the
1548 // last row and column of the inverse by 1/2, corresponding to the left
1549 // and right multiplication with mult^-1.
1550 const Number t4 = t.data[0][0] * t.data[1][1],
1551 t6 = t.data[0][0] * t.data[1][2],
1552 t8 = t.data[0][1] * t.data[1][0],
1553 t00 = t.data[0][2] * t.data[1][0],
1554 t01 = t.data[0][1] * t.data[2][0],
1555 t04 = t.data[0][2] * t.data[2][0],
1556 t07 = 1.0 / (t4 * t.data[2][2] - t6 * t.data[2][1] -
1557 t8 * t.data[2][2] + t00 * t.data[2][1] +
1558 t01 * t.data[1][2] - t04 * t.data[1][1]);
1559 tmp.data[0][0] =
1560 (t.data[1][1] * t.data[2][2] - t.data[1][2] * t.data[2][1]) * t07;
1561 tmp.data[0][1] =
1562 -(t.data[0][1] * t.data[2][2] - t.data[0][2] * t.data[2][1]) * t07;
1563 tmp.data[0][2] =
1564 -(-t.data[0][1] * t.data[1][2] + t.data[0][2] * t.data[1][1]) * t07;
1565 tmp.data[1][0] =
1566 -(t.data[1][0] * t.data[2][2] - t.data[1][2] * t.data[2][0]) * t07;
1567 tmp.data[1][1] = (t.data[0][0] * t.data[2][2] - t04) * t07;
1568 tmp.data[1][2] = -(t6 - t00) * t07;
1569 tmp.data[2][0] =
1570 -(-t.data[1][0] * t.data[2][1] + t.data[1][1] * t.data[2][0]) * t07;
1571 tmp.data[2][1] = -(t.data[0][0] * t.data[2][1] - t01) * t07;
1572 tmp.data[2][2] = (t4 - t8) * t07;
1573
1574 // scale last row and column as mentioned
1575 // above
1576 tmp.data[2][0] /= 2;
1577 tmp.data[2][1] /= 2;
1578 tmp.data[0][2] /= 2;
1579 tmp.data[1][2] /= 2;
1580 tmp.data[2][2] /= 4;
1581
1582 return tmp;
1583 }
1584 };
1585
1586
1587 template <typename Number>
1588 struct Inverse<4, 3, Number>
1589 {
1590 static ::SymmetricTensor<4, 3, Number>
1591 value(const ::SymmetricTensor<4, 3, Number> &t)
1592 {
1593 ::SymmetricTensor<4, 3, Number> tmp = t;
1594
1595 // This function follows the exact same scheme as the 2d case, except
1596 // that hardcoding the inverse of a 6x6 matrix is pretty wasteful.
1597 // Instead, we use the Gauss-Jordan algorithm implemented for
1598 // FullMatrix. For historical reasons the following code is copied from
1599 // there, with the tangential benefit that we do not need to copy the
1600 // tensor entries to and from the FullMatrix.
1601 const unsigned int N = 6;
1602
1603 // First get an estimate of the size of the elements of this matrix,
1604 // for later checks whether the pivot element is large enough, or
1605 // whether we have to fear that the matrix is not regular.
1606 Number diagonal_sum = internal::NumberType<Number>::value(0.0);
1607 for (unsigned int i = 0; i < N; ++i)
1608 diagonal_sum += numbers::NumberTraits<Number>::abs(tmp.data[i][i]);
1609 const Number typical_diagonal_element =
1610 diagonal_sum / static_cast<double>(N);
1611 (void)typical_diagonal_element;
1612
1613 unsigned int p[N];
1614 for (unsigned int i = 0; i < N; ++i)
1615 p[i] = i;
1616
1617 for (unsigned int j = 0; j < N; ++j)
1618 {
1619 // Pivot search: search that part of the line on and right of the
1620 // diagonal for the largest element.
1621 Number max = numbers::NumberTraits<Number>::abs(tmp.data[j][j]);
1622 unsigned int r = j;
1623 for (unsigned int i = j + 1; i < N; ++i)
1624 if (numbers::NumberTraits<Number>::abs(tmp.data[i][j]) > max)
1625 {
1627 r = i;
1628 }
1629
1630 // Check whether the pivot is too small
1631 Assert(max > 1.e-16 * typical_diagonal_element,
1632 ExcMessage("This tensor seems to be noninvertible"));
1633
1634 // Row interchange
1635 if (r > j)
1636 {
1637 for (unsigned int k = 0; k < N; ++k)
1638 std::swap(tmp.data[j][k], tmp.data[r][k]);
1639
1640 std::swap(p[j], p[r]);
1641 }
1642
1643 // Transformation
1644 const Number hr = 1. / tmp.data[j][j];
1645 tmp.data[j][j] = hr;
1646 for (unsigned int k = 0; k < N; ++k)
1647 {
1648 if (k == j)
1649 continue;
1650 for (unsigned int i = 0; i < N; ++i)
1651 {
1652 if (i == j)
1653 continue;
1654 tmp.data[i][k] -= tmp.data[i][j] * tmp.data[j][k] * hr;
1655 }
1656 }
1657 for (unsigned int i = 0; i < N; ++i)
1658 {
1659 tmp.data[i][j] *= hr;
1660 tmp.data[j][i] *= -hr;
1661 }
1662 tmp.data[j][j] = hr;
1663 }
1664
1665 // Column interchange
1666 Number hv[N];
1667 for (unsigned int i = 0; i < N; ++i)
1668 {
1669 for (unsigned int k = 0; k < N; ++k)
1670 hv[p[k]] = tmp.data[i][k];
1671 for (unsigned int k = 0; k < N; ++k)
1672 tmp.data[i][k] = hv[k];
1673 }
1674
1675 // Scale rows and columns. The mult matrix
1676 // here is diag[1, 1, 1, 1/2, 1/2, 1/2].
1677 for (unsigned int i = 3; i < 6; ++i)
1678 for (unsigned int j = 0; j < 3; ++j)
1679 tmp.data[i][j] /= 2;
1680
1681 for (unsigned int i = 0; i < 3; ++i)
1682 for (unsigned int j = 3; j < 6; ++j)
1683 tmp.data[i][j] /= 2;
1684
1685 for (unsigned int i = 3; i < 6; ++i)
1686 for (unsigned int j = 3; j < 6; ++j)
1687 tmp.data[i][j] /= 4;
1688
1689 return tmp;
1690 }
1691 };
1692
1693 } // namespace SymmetricTensorImplementation
1694} // namespace internal
1695
1696
1697
1698template <int rank_, int dim, typename Number>
1701 const
1702{
1703 return internal::SymmetricTensorImplementation::convert_to_tensor(*this);
1704}
1705
1706
1707
1708template <int rank_, int dim, typename Number>
1709DEAL_II_HOST constexpr bool
1712{
1713 return data == t.data;
1714}
1715
1716
1717
1718template <int rank_, int dim, typename Number>
1719DEAL_II_HOST constexpr bool
1722{
1723 return data != t.data;
1724}
1725
1726
1727
1728template <int rank_, int dim, typename Number>
1729template <typename OtherNumber>
1730DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
1734{
1735 data += t.data;
1736 return *this;
1737}
1738
1739
1740
1741template <int rank_, int dim, typename Number>
1742template <typename OtherNumber>
1743DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
1747{
1748 data -= t.data;
1749 return *this;
1750}
1751
1752
1753
1754template <int rank_, int dim, typename Number>
1755template <typename OtherNumber>
1756DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
1759{
1760 data *= d;
1761 return *this;
1762}
1763
1764
1765
1766template <int rank_, int dim, typename Number>
1767template <typename OtherNumber>
1768DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
1771{
1772 data /= d;
1773 return *this;
1774}
1775
1776
1777
1778template <int rank_, int dim, typename Number>
1779DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
1782{
1783 SymmetricTensor tmp = *this;
1784 tmp.data = -tmp.data;
1785 return tmp;
1786}
1787
1788
1789
1790template <int rank_, int dim, typename Number>
1791DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE void
1793{
1794 data.clear();
1795}
1796
1797
1798
1799template <int rank_, int dim, typename Number>
1800DEAL_II_HOST constexpr std::size_t
1802{
1803 // all memory consists of statically allocated memory of the current
1804 // object, no pointers
1806}
1807
1808
1809
1810namespace internal
1811{
1815 template <int dim, typename Number, typename OtherNumber = Number>
1817 typename SymmetricTensorAccessors::
1818 double_contraction_result<2, 2, dim, Number, OtherNumber>::type
1819 perform_double_contraction(
1821 base_tensor_type &data,
1822 const typename SymmetricTensorAccessors::
1823 StorageType<2, dim, OtherNumber>::base_tensor_type &sdata)
1824 {
1825 using result_type = typename SymmetricTensorAccessors::
1826 double_contraction_result<2, 2, dim, Number, OtherNumber>::type;
1827
1828 switch (dim)
1829 {
1830 case 1:
1831 return data[0] * sdata[0];
1832
1833 default:
1834 // Start with the non-diagonal part. These values appear
1835 // twice in the matrix, but are only stored once. So we can
1836 // get the double-contraction sum for these elements using
1837 // only one multiplication each, and at the end multiplying
1838 // things by 2.
1839 result_type sum = data[dim] * sdata[dim];
1840 for (unsigned int d = dim + 1; d < (dim * (dim + 1) / 2); ++d)
1841 sum += data[d] * sdata[d];
1842 sum += sum; // sum *= 2
1843
1844 // Now add the contributions from the diagonal
1845 for (unsigned int d = 0; d < dim; ++d)
1846 sum += data[d] * sdata[d];
1847 return sum;
1848 }
1849 }
1850
1851
1852
1857 template <int dim, typename Number, typename OtherNumber = Number>
1859 typename SymmetricTensorAccessors::
1860 double_contraction_result<4, 2, dim, Number, OtherNumber>::type
1861 perform_double_contraction(
1863 base_tensor_type &data,
1864 const typename SymmetricTensorAccessors::
1865 StorageType<2, dim, OtherNumber>::base_tensor_type &sdata)
1866 {
1867 using result_type = typename SymmetricTensorAccessors::
1868 double_contraction_result<4, 2, dim, Number, OtherNumber>::type;
1869 using value_type = typename SymmetricTensorAccessors::
1870 double_contraction_result<4, 2, dim, Number, OtherNumber>::value_type;
1871
1872 const unsigned int data_dim = SymmetricTensorAccessors::
1873 StorageType<2, dim, value_type>::n_independent_components;
1874 value_type tmp[data_dim]{};
1875 for (unsigned int i = 0; i < data_dim; ++i)
1876 tmp[i] =
1877 perform_double_contraction<dim, Number, OtherNumber>(data[i], sdata);
1878 return result_type(tmp);
1879 }
1880
1881
1882
1887 template <int dim, typename Number, typename OtherNumber = Number>
1890 2,
1891 dim,
1892 typename SymmetricTensorAccessors::
1893 double_contraction_result<2, 4, dim, Number, OtherNumber>::value_type>::
1894 base_tensor_type
1895 perform_double_contraction(
1897 base_tensor_type &data,
1898 const typename SymmetricTensorAccessors::
1899 StorageType<4, dim, OtherNumber>::base_tensor_type &sdata)
1900 {
1901 using value_type = typename SymmetricTensorAccessors::
1902 double_contraction_result<2, 4, dim, Number, OtherNumber>::value_type;
1903 using base_tensor_type = typename SymmetricTensorAccessors::
1904 StorageType<2, dim, value_type>::base_tensor_type;
1905
1906 base_tensor_type tmp;
1907 for (unsigned int i = 0; i < tmp.dimension; ++i)
1908 {
1909 // Start with the non-diagonal part. These values appear
1910 // twice in the matrix, but are only stored once. So we can
1911 // get the double-contraction sum for these elements using
1912 // only one multiplication each, and at the end multiplying
1913 // things by 2.
1914 value_type sum = data[dim] * sdata[dim][i];
1915 for (unsigned int d = dim + 1; d < (dim * (dim + 1) / 2); ++d)
1916 sum += data[d] * sdata[d][i];
1917 sum += sum; // sum *= 2
1918
1919 // Now add the contributions from the diagonal
1920 for (unsigned int d = 0; d < dim; ++d)
1921 sum += data[d] * sdata[d][i];
1922 tmp[i] = sum;
1923 }
1924 return tmp;
1925 }
1926
1927
1928
1932 template <int dim, typename Number, typename OtherNumber = Number>
1935 4,
1936 dim,
1937 typename SymmetricTensorAccessors::
1938 double_contraction_result<4, 4, dim, Number, OtherNumber>::value_type>::
1939 base_tensor_type
1940 perform_double_contraction(
1942 base_tensor_type &data,
1943 const typename SymmetricTensorAccessors::
1944 StorageType<4, dim, OtherNumber>::base_tensor_type &sdata)
1945 {
1946 using value_type = typename SymmetricTensorAccessors::
1947 double_contraction_result<4, 4, dim, Number, OtherNumber>::value_type;
1948 using base_tensor_type = typename SymmetricTensorAccessors::
1949 StorageType<4, dim, value_type>::base_tensor_type;
1950
1951 const unsigned int data_dim = SymmetricTensorAccessors::
1952 StorageType<2, dim, value_type>::n_independent_components;
1953 base_tensor_type tmp;
1954 for (unsigned int i = 0; i < data_dim; ++i)
1955 for (unsigned int j = 0; j < data_dim; ++j)
1956 {
1957 // Start with the non-diagonal part
1958 for (unsigned int d = dim; d < (dim * (dim + 1) / 2); ++d)
1959 tmp[i][j] += data[i][d] * sdata[d][j];
1960 tmp[i][j] += tmp[i][j]; // tmp[i][j] *= 2;
1961
1962 // Now add the contributions from the diagonal
1963 for (unsigned int d = 0; d < dim; ++d)
1964 tmp[i][j] += data[i][d] * sdata[d][j];
1965 }
1966 return tmp;
1967 }
1968
1969} // end of namespace internal
1970
1971
1972
1973template <int rank_, int dim, typename Number>
1974template <typename OtherNumber>
1976 typename internal::SymmetricTensorAccessors::
1977 double_contraction_result<rank_, 2, dim, Number, OtherNumber>::type
1980{
1981 // Dispatch to functions that know the types of the involved
1982 // arguments via overloads.
1983 return internal::perform_double_contraction<dim, Number, OtherNumber>(data,
1984 s.data);
1985}
1986
1987
1988
1989template <int rank_, int dim, typename Number>
1990template <typename OtherNumber>
1992 typename internal::SymmetricTensorAccessors::
1993 double_contraction_result<rank_, 4, dim, Number, OtherNumber>::type
1996{
1997 typename internal::SymmetricTensorAccessors::
1998 double_contraction_result<rank_, 4, dim, Number, OtherNumber>::type tmp;
1999 tmp.data =
2000 internal::perform_double_contraction<dim, Number, OtherNumber>(data,
2001 s.data);
2002 return tmp;
2003}
2004
2005
2006
2007// internal namespace to switch between the
2008// access of different tensors. There used to
2009// be explicit instantiations before for
2010// different ranks and dimensions, but since
2011// we now allow for templates on the data
2012// type, and since we cannot partially
2013// specialize the implementation, this got
2014// into a separate namespace
2015namespace internal
2016{
2018 {
2019 // a function to do the unrolling from a set of indices to a
2020 // scalar index into the array in which we store the elements of
2021 // a symmetric tensor
2022 //
2023 // this function is for rank-2 tensors
2024 template <int dim>
2025 constexpr inline DEAL_II_ALWAYS_INLINE unsigned int
2026 component_to_unrolled_index(const TableIndices<2> &indices)
2027 {
2028 AssertIndexRange(indices[0], dim);
2029 AssertIndexRange(indices[1], dim);
2030
2031 switch (dim)
2032 {
2033 case 1:
2034 {
2035 return 0;
2036 }
2037 case 2:
2038 {
2039 constexpr ::ndarray<unsigned int, 2, 2> table = {
2040 {{{0, 2}}, {{2, 1}}}};
2041 return table[indices[0]][indices[1]];
2042 }
2043 case 3:
2044 {
2045 constexpr ::ndarray<unsigned int, 3, 3> table = {
2046 {{{0, 3, 4}}, {{3, 1, 5}}, {{4, 5, 2}}}};
2047 return table[indices[0]][indices[1]];
2048 }
2049 case 4:
2050 {
2051 constexpr ::ndarray<unsigned int, 4, 4> table = {
2052 {{{0, 4, 5, 6}},
2053 {{4, 1, 7, 8}},
2054 {{5, 7, 2, 9}},
2055 {{6, 8, 9, 3}}}};
2056 return table[indices[0]][indices[1]];
2057 }
2058 default:
2059 // for the remainder, manually figure out the numbering
2060 {
2061 if (indices[0] == indices[1])
2062 return indices[0];
2063
2064 const TableIndices<2> sorted_indices(
2065 std::min(indices[0], indices[1]),
2066 std::max(indices[0], indices[1]));
2067
2068 // Here (d, e) are the row and column of the symmetric matrix and
2069 // 'dim + c' is the index into the Tensor<1, dim> actually used
2070 // for storage.
2071 unsigned int c = 0;
2072 for (unsigned int d = 0; d < dim; ++d)
2073 for (unsigned int e = d + 1; e < dim; ++e, ++c)
2074 if ((sorted_indices[0] == d) && (sorted_indices[1] == e))
2075 return dim + c;
2076
2077 // should never get here:
2079 return 0;
2080 }
2081 }
2082 }
2083
2084 // a function to do the unrolling from a set of indices to a
2085 // scalar index into the array in which we store the elements of
2086 // a symmetric tensor
2087 //
2088 // this function is for tensors of ranks not already handled
2089 // above
2090 template <int dim, int rank_>
2091 constexpr inline unsigned int
2092 component_to_unrolled_index(const TableIndices<rank_> &indices)
2093 {
2094 (void)indices;
2097 }
2098 } // namespace SymmetricTensorImplementation
2099
2100 template <int dim, typename Number>
2101 constexpr inline DEAL_II_ALWAYS_INLINE Number &
2102 symmetric_tensor_access(const TableIndices<2> &indices,
2103 typename SymmetricTensorAccessors::
2104 StorageType<2, dim, Number>::base_tensor_type &data)
2105 {
2107 indices)];
2108 }
2109
2110
2111
2112 template <int dim, typename Number>
2113 constexpr inline DEAL_II_ALWAYS_INLINE const Number &
2114 symmetric_tensor_access(const TableIndices<2> &indices,
2115 const typename SymmetricTensorAccessors::
2116 StorageType<2, dim, Number>::base_tensor_type &data)
2117 {
2119 indices)];
2120 }
2121
2122
2123
2124 template <int dim, typename Number>
2125 constexpr inline Number &
2126 symmetric_tensor_access(const TableIndices<4> &indices,
2127 typename SymmetricTensorAccessors::
2128 StorageType<4, dim, Number>::base_tensor_type &data)
2129 {
2130 switch (dim)
2131 {
2132 case 1:
2133 return data[0][0];
2134
2135 case 2:
2136 // each entry of the tensor can be thought of as an entry in a
2137 // matrix that maps the rolled-out rank-2 tensors into rolled-out
2138 // rank-2 tensors. this is the format in which we store rank-4
2139 // tensors. determine which position the present entry is
2140 // stored in
2141 {
2142 constexpr std::size_t base_index[2][2] = {{0, 2}, {2, 1}};
2143 return data[base_index[indices[0]][indices[1]]]
2144 [base_index[indices[2]][indices[3]]];
2145 }
2146 case 3:
2147 // each entry of the tensor can be thought of as an entry in a
2148 // matrix that maps the rolled-out rank-2 tensors into rolled-out
2149 // rank-2 tensors. this is the format in which we store rank-4
2150 // tensors. determine which position the present entry is
2151 // stored in
2152 {
2153 constexpr std::size_t base_index[3][3] = {{0, 3, 4},
2154 {3, 1, 5},
2155 {4, 5, 2}};
2156 return data[base_index[indices[0]][indices[1]]]
2157 [base_index[indices[2]][indices[3]]];
2158 }
2159
2160 default:
2162 }
2163
2164 // The code should never reach here.
2165 // We cannot return a static variable, as this class must support number
2166 // types that require no instances of the number type to be in scope during
2167 // a reinitialization procedure (e.g. ADOL-C adtl::adouble).
2168 return data[0][0];
2169 }
2170
2171
2172 template <int dim, typename Number>
2173 constexpr inline DEAL_II_ALWAYS_INLINE const Number &
2174 symmetric_tensor_access(const TableIndices<4> &indices,
2175 const typename SymmetricTensorAccessors::
2176 StorageType<4, dim, Number>::base_tensor_type &data)
2177 {
2178 switch (dim)
2179 {
2180 case 1:
2181 return data[0][0];
2182
2183 case 2:
2184 // each entry of the tensor can be thought of as an entry in a
2185 // matrix that maps the rolled-out rank-2 tensors into rolled-out
2186 // rank-2 tensors. this is the format in which we store rank-4
2187 // tensors. determine which position the present entry is
2188 // stored in
2189 {
2190 constexpr std::size_t base_index[2][2] = {{0, 2}, {2, 1}};
2191 return data[base_index[indices[0]][indices[1]]]
2192 [base_index[indices[2]][indices[3]]];
2193 }
2194 case 3:
2195 // each entry of the tensor can be thought of as an entry in a
2196 // matrix that maps the rolled-out rank-2 tensors into rolled-out
2197 // rank-2 tensors. this is the format in which we store rank-4
2198 // tensors. determine which position the present entry is
2199 // stored in
2200 {
2201 constexpr std::size_t base_index[3][3] = {{0, 3, 4},
2202 {3, 1, 5},
2203 {4, 5, 2}};
2204 return data[base_index[indices[0]][indices[1]]]
2205 [base_index[indices[2]][indices[3]]];
2206 }
2207
2208 default:
2210 }
2211
2212 // The code should never reach here.
2213 // We cannot return a static variable, as this class must support number
2214 // types that require no instances of the number type to be in scope during
2215 // a reinitialization procedure (e.g. ADOL-C adtl::adouble).
2216 return data[0][0];
2217 }
2218
2219} // end of namespace internal
2220
2221
2222
2223template <int rank_, int dim, typename Number>
2224DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE Number &
2226 const TableIndices<rank_> &indices)
2227{
2228 for (unsigned int r = 0; r < rank; ++r)
2229 AssertIndexRange(indices[r], dimension);
2230 return internal::symmetric_tensor_access<dim, Number>(indices, data);
2231}
2232
2233
2234
2235template <int rank_, int dim, typename Number>
2236DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE const Number &
2238 const TableIndices<rank_> &indices) const
2239{
2240 for (unsigned int r = 0; r < rank; ++r)
2241 AssertIndexRange(indices[r], dimension);
2242 return internal::symmetric_tensor_access<dim, Number>(indices, data);
2243}
2244
2245
2246
2247namespace internal
2248{
2250 {
2251 template <int rank_>
2252 constexpr TableIndices<rank_>
2253 get_partially_filled_indices(const unsigned int row,
2254 const std::integral_constant<int, 2> &)
2255 {
2256 return TableIndices<rank_>(row, numbers::invalid_unsigned_int);
2257 }
2258
2259
2260 template <int rank_>
2261 constexpr TableIndices<rank_>
2262 get_partially_filled_indices(const unsigned int row,
2263 const std::integral_constant<int, 4> &)
2264 {
2265 return TableIndices<rank_>(row,
2269 }
2270 } // namespace SymmetricTensorImplementation
2271} // namespace internal
2272
2273
2274template <int rank_, int dim, typename Number>
2275DEAL_II_HOST constexpr DEAL_II_ALWAYS_INLINE internal::
2276 SymmetricTensorAccessors::Accessor<rank_, dim, true, rank_ - 1, Number>
2277 SymmetricTensor<rank_, dim, Number>::operator[](const unsigned int row) const
2278{
2279 return internal::SymmetricTensorAccessors::
2280 Accessor<rank_, dim, true, rank_ - 1, Number>(
2281 *this,
2282 internal::SymmetricTensorImplementation::get_partially_filled_indices<
2283 rank_>(row, std::integral_constant<int, rank_>()));
2284}
2285
2286
2287
2288template <int rank_, int dim, typename Number>
2289DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE internal::
2290 SymmetricTensorAccessors::Accessor<rank_, dim, false, rank_ - 1, Number>
2292{
2293 return internal::SymmetricTensorAccessors::
2294 Accessor<rank_, dim, false, rank_ - 1, Number>(
2295 *this,
2296 internal::SymmetricTensorImplementation::get_partially_filled_indices<
2297 rank_>(row, std::integral_constant<int, rank_>()));
2298}
2299
2300
2301
2302template <int rank_, int dim, typename Number>
2303DEAL_II_HOST constexpr DEAL_II_ALWAYS_INLINE const Number &
2305 const TableIndices<rank_> &indices) const
2306{
2307 return operator()(indices);
2308}
2309
2310
2311
2312template <int rank_, int dim, typename Number>
2313DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE Number &
2315 const TableIndices<rank_> &indices)
2316{
2317 return operator()(indices);
2318}
2319
2320
2321
2322template <int rank_, int dim, typename Number>
2323DEAL_II_HOST constexpr inline const Number &
2325 const unsigned int index) const
2326{
2327 AssertIndexRange(index, n_independent_components);
2328 if constexpr (rank == 2)
2329 return data[index];
2330 else
2331 return data[decltype(data)::unrolled_to_component_indices(index)];
2332}
2333
2334
2335
2336template <int rank_, int dim, typename Number>
2337DEAL_II_HOST constexpr inline Number &
2339{
2340 AssertIndexRange(index, n_independent_components);
2341 if constexpr (rank == 2)
2342 return data[index];
2343 else
2344 return data[decltype(data)::unrolled_to_component_indices(index)];
2345}
2346
2347
2348
2349namespace internal
2350{
2351 template <int dim, typename Number>
2352 constexpr inline typename numbers::NumberTraits<Number>::real_type
2353 compute_norm(const typename SymmetricTensorAccessors::
2354 StorageType<2, dim, Number>::base_tensor_type &data)
2355 {
2356 // Make things work with AD types
2357 using std::sqrt;
2358 switch (dim)
2359 {
2360 case 1:
2361 return numbers::NumberTraits<Number>::abs(data[0]);
2362
2363 case 2:
2367
2368 case 3:
2375
2376 default:
2377 {
2378 typename numbers::NumberTraits<Number>::real_type return_value =
2380
2381 for (unsigned int d = 0; d < dim; ++d)
2382 return_value +=
2384 for (unsigned int d = dim; d < (dim * dim + dim) / 2; ++d)
2385 return_value +=
2387
2388 return sqrt(return_value);
2389 }
2390 }
2391 }
2392
2393
2394
2395 template <int dim, typename Number>
2396 constexpr inline typename numbers::NumberTraits<Number>::real_type
2397 compute_norm(const typename SymmetricTensorAccessors::
2398 StorageType<4, dim, Number>::base_tensor_type &data)
2399 {
2400 // Make things work with AD types
2401 using std::sqrt;
2402 switch (dim)
2403 {
2404 case 1:
2405 return numbers::NumberTraits<Number>::abs(data[0][0]);
2406
2407 default:
2408 {
2409 typename numbers::NumberTraits<Number>::real_type return_value =
2411
2412 const unsigned int n_independent_components = data.dimension;
2413
2414 for (unsigned int i = 0; i < dim; ++i)
2415 for (unsigned int j = 0; j < dim; ++j)
2416 return_value +=
2418 for (unsigned int i = 0; i < dim; ++i)
2419 for (unsigned int j = dim; j < n_independent_components; ++j)
2420 return_value +=
2422 for (unsigned int i = dim; i < n_independent_components; ++i)
2423 for (unsigned int j = 0; j < dim; ++j)
2424 return_value +=
2426 for (unsigned int i = dim; i < n_independent_components; ++i)
2427 for (unsigned int j = dim; j < n_independent_components; ++j)
2428 return_value +=
2430
2431 return sqrt(return_value);
2432 }
2433 }
2434 }
2435
2436} // end of namespace internal
2437
2438
2439
2440template <int rank_, int dim, typename Number>
2443{
2444 return internal::compute_norm<dim, Number>(data);
2445}
2446
2447
2448
2449template <int rank_, int dim, typename Number>
2450DEAL_II_HOST constexpr unsigned int
2452 const TableIndices<rank_> &indices)
2453{
2454 return internal::SymmetricTensorImplementation::component_to_unrolled_index<
2455 dim>(indices);
2456}
2457
2458
2459
2460namespace internal
2461{
2463 {
2464 // a function to do the inverse of the unrolling from a set of
2465 // indices to a scalar index into the array in which we store
2466 // the elements of a symmetric tensor. in other words, it goes
2467 // from the scalar index into the array to a set of indices of
2468 // the tensor
2469 //
2470 // this function is for rank-2 tensors
2471 template <int dim>
2472 constexpr inline DEAL_II_ALWAYS_INLINE TableIndices<2>
2473 unrolled_to_component_indices(const unsigned int i,
2474 const std::integral_constant<int, 2> &)
2475 {
2476 Assert(
2479 i,
2480 0,
2482 switch (dim)
2483 {
2484 case 1:
2485 {
2486 return {0, 0};
2487 }
2488
2489 case 2:
2490 {
2491 const TableIndices<2> table[3] = {TableIndices<2>(0, 0),
2492 TableIndices<2>(1, 1),
2493 TableIndices<2>(0, 1)};
2494 return table[i];
2495 }
2496
2497 case 3:
2498 {
2499 const TableIndices<2> table[6] = {TableIndices<2>(0, 0),
2500 TableIndices<2>(1, 1),
2501 TableIndices<2>(2, 2),
2502 TableIndices<2>(0, 1),
2503 TableIndices<2>(0, 2),
2504 TableIndices<2>(1, 2)};
2505 return table[i];
2506 }
2507
2508 default:
2509 if (i < dim)
2510 return {i, i};
2511
2512 for (unsigned int d = 0, c = dim; d < dim; ++d)
2513 for (unsigned int e = d + 1; e < dim; ++e, ++c)
2514 if (c == i)
2515 return {d, e};
2516
2517 // should never get here:
2519 return {0, 0};
2520 }
2521 }
2522
2523 // a function to do the inverse of the unrolling from a set of
2524 // indices to a scalar index into the array in which we store
2525 // the elements of a symmetric tensor. in other words, it goes
2526 // from the scalar index into the array to a set of indices of
2527 // the tensor
2528 //
2529 // this function is for tensors of a rank not already handled
2530 // above
2531 template <int dim, int rank_>
2532 constexpr inline std::enable_if_t<rank_ != 2, TableIndices<rank_>>
2533 unrolled_to_component_indices(const unsigned int i,
2534 const std::integral_constant<int, rank_> &)
2535 {
2536 (void)i;
2537 Assert(
2538 (i <
2540 ExcIndexRange(i,
2541 0,
2542 ::SymmetricTensor<rank_, dim, double>::
2543 n_independent_components));
2545 return TableIndices<rank_>();
2546 }
2547
2548 } // namespace SymmetricTensorImplementation
2549} // namespace internal
2550
2551template <int rank_, int dim, typename Number>
2554 const unsigned int i)
2555{
2556 return internal::SymmetricTensorImplementation::unrolled_to_component_indices<
2557 dim>(i, std::integral_constant<int, rank_>());
2558}
2559
2560
2561
2562template <int rank_, int dim, typename Number>
2563template <class Archive>
2564inline void
2565SymmetricTensor<rank_, dim, Number>::serialize(Archive &ar, const unsigned int)
2566{
2567 ar &data;
2568}
2569
2570
2571#endif // DOXYGEN
2572
2573/* ----------------- Non-member functions operating on tensors. ------------ */
2574
2575
2588template <int rank_, int dim, typename Number, typename OtherNumber>
2589DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
2599
2600
2613template <int rank_, int dim, typename Number, typename OtherNumber>
2614DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
2624
2625
2633template <int rank_, int dim, typename Number, typename OtherNumber>
2638{
2639 return Tensor<rank_, dim, Number>(left) + right;
2640}
2641
2642
2650template <int rank_, int dim, typename Number, typename OtherNumber>
2655{
2656 return left + Tensor<rank_, dim, OtherNumber>(right);
2657}
2658
2659
2667template <int rank_, int dim, typename Number, typename OtherNumber>
2672{
2673 return Tensor<rank_, dim, Number>(left) - right;
2674}
2675
2676
2684template <int rank_, int dim, typename Number, typename OtherNumber>
2689{
2690 return left - Tensor<rank_, dim, OtherNumber>(right);
2691}
2692
2693
2694
2695template <int dim, typename Number>
2698{
2699 switch (dim)
2700 {
2701 case 1:
2702 return t.data[0];
2703 case 2:
2704 return (t.data[0] * t.data[1] - t.data[2] * t.data[2]);
2705 case 3:
2706 {
2707 // in analogy to general tensors, but
2708 // there's something to be simplified for
2709 // the present case
2710 const Number tmp = t.data[3] * t.data[4] * t.data[5];
2711 return (tmp + tmp + t.data[0] * t.data[1] * t.data[2] -
2712 t.data[0] * t.data[5] * t.data[5] -
2713 t.data[1] * t.data[4] * t.data[4] -
2714 t.data[2] * t.data[3] * t.data[3]);
2715 }
2716 default:
2719 }
2720}
2721
2722
2723
2735template <int dim, typename Number>
2741
2742
2743
2744template <int dim, typename Number>
2745DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE Number
2747{
2748 Number t = d.data[0];
2749 for (unsigned int i = 1; i < dim; ++i)
2750 t += d.data[i];
2751 return t;
2752}
2753
2754
2766template <int dim, typename Number>
2767DEAL_II_HOST constexpr Number
2769{
2770 return trace(t);
2771}
2772
2773
2785template <typename Number>
2786DEAL_II_HOST constexpr DEAL_II_ALWAYS_INLINE Number
2791
2792
2793
2812template <typename Number>
2813DEAL_II_HOST constexpr DEAL_II_ALWAYS_INLINE Number
2815{
2816 return t[0][0] * t[1][1] - t[0][1] * t[0][1];
2817}
2818
2819
2820
2829template <typename Number>
2830DEAL_II_HOST constexpr DEAL_II_ALWAYS_INLINE Number
2832{
2833 return (t[0][0] * t[1][1] + t[1][1] * t[2][2] + t[2][2] * t[0][0] -
2834 t[0][1] * t[0][1] - t[0][2] * t[0][2] - t[1][2] * t[1][2]);
2835}
2836
2837
2838
2846template <typename Number>
2847std::array<Number, 1>
2849
2850
2851
2874template <typename Number>
2875std::array<Number, 2>
2877
2878
2879
2902template <typename Number>
2903std::array<Number, 3>
2905
2906
2907
2908namespace internal
2909{
2910 namespace SymmetricTensorImplementation
2911 {
2923 template <int dim, typename Number>
2924 void
2925 tridiagonalize(const ::SymmetricTensor<2, dim, Number> &A,
2927 std::array<Number, dim> &d,
2928 std::array<Number, dim - 1> &e);
2929
2930
2931
2945 template <int dim, typename Number>
2946 std::array<std::pair<Number, Tensor<1, dim, Number>>, dim>
2947 ql_implicit_shifts(const ::SymmetricTensor<2, dim, Number> &A);
2948
2949
2950
2964 template <int dim, typename Number>
2965 std::array<std::pair<Number, Tensor<1, dim, Number>>, dim>
2967
2968
2969
2983 template <typename Number>
2984 std::array<std::pair<Number, Tensor<1, 2, Number>>, 2>
2985 hybrid(const ::SymmetricTensor<2, 2, Number> &A);
2986
2987
2988
3003 template <typename Number>
3004 std::array<std::pair<Number, Tensor<1, 3, Number>>, 3>
3005 hybrid(const ::SymmetricTensor<2, 3, Number> &A);
3006
3011 template <int dim, typename Number>
3013 {
3014 using EigValsVecs = std::pair<Number, Tensor<1, dim, Number>>;
3015 bool
3016 operator()(const EigValsVecs &lhs, const EigValsVecs &rhs)
3017 {
3018 return lhs.first > rhs.first;
3019 }
3020 };
3021
3022 } // namespace SymmetricTensorImplementation
3023
3024} // namespace internal
3025
3026
3027
3028// The line below is to ensure that doxygen puts the full description
3029// of this global enumeration into the documentation
3030// See https://stackoverflow.com/a/1717984
3072
3073
3074
3085template <int dim, typename Number>
3086std::array<std::pair<Number, Tensor<1, dim, Number>>, dim>
3090
3091
3092
3101template <int rank_, int dim, typename Number>
3104{
3105 return t;
3106}
3107
3108
3109
3110template <int dim, typename Number>
3111DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
3114{
3116
3117 // subtract scaled trace from the diagonal
3118 const Number tr = trace(t) * internal::NumberType<Number>::value(1.0 / dim);
3119 for (unsigned int i = 0; i < dim; ++i)
3120 tmp.data[i] -= tr;
3121
3122 return tmp;
3123}
3124
3125
3126
3127template <int dim, typename Number>
3131{
3132 // create a default constructed matrix filled with
3133 // zeros, then set the diagonal elements to one
3135 switch (dim)
3136 {
3137 case 1:
3139 break;
3140 case 2:
3141 tmp.data[0] = tmp.data[1] = internal::NumberType<Number>::value(1.);
3142 break;
3143 case 3:
3144 tmp.data[0] = tmp.data[1] = tmp.data[2] =
3146 break;
3147 default:
3148 for (unsigned int d = 0; d < dim; ++d)
3150 }
3151 return tmp;
3152}
3153
3154
3155
3156template <int dim, typename Number>
3159{
3161
3162 // fill the elements treating the diagonal
3163 for (unsigned int i = 0; i < dim; ++i)
3164 for (unsigned int j = 0; j < dim; ++j)
3165 tmp.data[i][j] =
3166 internal::NumberType<Number>::value((i == j ? 1. : 0.) - 1. / dim);
3167
3168 // then fill the ones that copy over the
3169 // non-diagonal elements. note that during
3170 // the double-contraction, we handle the
3171 // off-diagonal elements twice, so simply
3172 // copying requires a weight of 1/2
3173 for (unsigned int i = dim;
3174 i < internal::SymmetricTensorAccessors::StorageType<4, dim, Number>::
3175 n_rank2_components;
3176 ++i)
3178
3179 return tmp;
3180}
3181
3182
3183
3184template <int dim, typename Number>
3188{
3190
3191 // fill the elements treating the diagonal
3192 for (unsigned int i = 0; i < dim; ++i)
3194
3195 // then fill the ones that copy over the
3196 // non-diagonal elements. note that during
3197 // the double-contraction, we handle the
3198 // off-diagonal elements twice, so simply
3199 // copying requires a weight of 1/2
3200 for (unsigned int i = dim;
3201 i < internal::SymmetricTensorAccessors::StorageType<4, dim, Number>::
3202 n_rank2_components;
3203 ++i)
3205
3206 return tmp;
3207}
3208
3209
3210
3220template <int dim, typename Number>
3227
3228
3229
3240template <int dim, typename Number>
3247
3248
3249
3271template <int dim, typename Number>
3275{
3277
3278 // fill only the elements really needed
3279 for (unsigned int i = 0; i < dim; ++i)
3280 for (unsigned int j = i; j < dim; ++j)
3281 for (unsigned int k = 0; k < dim; ++k)
3282 for (unsigned int l = k; l < dim; ++l)
3283 tmp[i][j][k][l] = t1[i][j] * t2[k][l];
3284
3285 return tmp;
3286}
3287
3313template <int dim, typename Number>
3314std::pair<SymmetricTensor<2, dim, Number>, SymmetricTensor<2, dim, Number>>
3316{
3317 Assert(dim <= 3, ExcNotImplemented());
3318
3319 const std::array<std::pair<Number, Tensor<1, dim, Number>>, dim>
3320 eigen_system = eigenvectors(original_tensor);
3321
3322 std::pair<SymmetricTensor<2, dim, Number>, SymmetricTensor<2, dim, Number>>
3323 positive_negative_tensors;
3324
3325 auto &[positive_part_tensor, negative_part_tensor] =
3326 positive_negative_tensors;
3327
3328 positive_part_tensor = 0;
3329 for (unsigned int i = 0; i < dim; ++i)
3330 if (eigen_system[i].first > 0)
3331 positive_part_tensor += eigen_system[i].first *
3332 symmetrize(outer_product(eigen_system[i].second,
3333 eigen_system[i].second));
3334
3335 negative_part_tensor = 0;
3336 for (unsigned int i = 0; i < dim; ++i)
3337 if (eigen_system[i].first < 0)
3338 negative_part_tensor += eigen_system[i].first *
3339 symmetrize(outer_product(eigen_system[i].second,
3340 eigen_system[i].second));
3341
3342 return positive_negative_tensors;
3343}
3344
3377template <int dim, typename Number>
3378std::tuple<SymmetricTensor<2, dim, Number>,
3383 const SymmetricTensor<2, dim, Number> &original_tensor)
3384{
3385 Assert(dim <= 3, ExcNotImplemented());
3386
3387 auto heaviside_function{[](const double x) {
3388 if (std::fabs(x) < 1.0e-16)
3389 return 0.5;
3390 if (x > 0)
3391 return 1.0;
3392 else
3393 return 0.0;
3394 }};
3395
3396 std::tuple<SymmetricTensor<2, dim, Number>,
3400 positive_negative_tensors_projectors;
3401
3402 auto &[positive_part_tensor,
3403 negative_part_tensor,
3404 positive_projector,
3405 negative_projector] = positive_negative_tensors_projectors;
3406
3407 const std::array<std::pair<Number, Tensor<1, dim, Number>>, dim>
3408 eigen_system = eigenvectors(original_tensor);
3409
3410 positive_part_tensor = 0;
3411 for (unsigned int i = 0; i < dim; ++i)
3412 if (eigen_system[i].first > 0)
3413 positive_part_tensor += eigen_system[i].first *
3414 symmetrize(outer_product(eigen_system[i].second,
3415 eigen_system[i].second));
3416
3417 negative_part_tensor = 0;
3418 for (unsigned int i = 0; i < dim; ++i)
3419 if (eigen_system[i].first < 0)
3420 negative_part_tensor += eigen_system[i].first *
3421 symmetrize(outer_product(eigen_system[i].second,
3422 eigen_system[i].second));
3423
3424 std::array<SymmetricTensor<2, dim, Number>, dim> M;
3425 for (unsigned int a = 0; a < dim; ++a)
3426 M[a] =
3427 symmetrize(outer_product(eigen_system[a].second, eigen_system[a].second));
3428
3429 std::array<SymmetricTensor<4, dim, Number>, dim> Q;
3430 for (unsigned int a = 0; a < dim; ++a)
3431 Q[a] = outer_product(M[a], M[a]);
3432
3433 std::array<std::array<SymmetricTensor<4, dim, Number>, dim>, dim> G;
3434 for (unsigned int a = 0; a < dim; ++a)
3435 for (unsigned int b = 0; b < dim; ++b)
3436 for (unsigned int i = 0; i < dim; ++i)
3437 for (unsigned int j = 0; j < dim; ++j)
3438 for (unsigned int k = 0; k < dim; ++k)
3439 for (unsigned int l = 0; l < dim; ++l)
3440 G[a][b][i][j][k][l] =
3441 M[a][i][k] * M[b][j][l] + M[a][i][l] * M[b][j][k];
3442
3443 // positive P
3444 positive_projector = 0;
3445 for (unsigned int a = 0; a < dim; ++a)
3446 {
3447 double lambda_a = eigen_system[a].first;
3448 positive_projector += heaviside_function(lambda_a) * Q[a];
3449 for (unsigned int b = 0; b < dim; ++b)
3450 {
3451 if (b != a)
3452 {
3453 double lambda_b = eigen_system[b].first;
3454
3455 double v_ab = 0.0;
3456 if (std::fabs(lambda_a - lambda_b) > 1.0e-12)
3457 v_ab = (std::fmax(lambda_a, 0.0) - std::fmax(lambda_b, 0.0)) /
3458 (lambda_a - lambda_b);
3459 else
3460 v_ab = 0.5 * (heaviside_function(lambda_a) +
3461 heaviside_function(lambda_b));
3462
3463 positive_projector += 0.5 * v_ab * 0.5 * (G[a][b] + G[b][a]);
3464 }
3465 }
3466 }
3467
3468 // negative P
3469 negative_projector = 0;
3470 for (unsigned int a = 0; a < dim; ++a)
3471 {
3472 double lambda_a = eigen_system[a].first;
3473 negative_projector += heaviside_function(-lambda_a) * Q[a];
3474 for (unsigned int b = 0; b < dim; ++b)
3475 {
3476 if (b != a)
3477 {
3478 double lambda_b = eigen_system[b].first;
3479
3480 double v_ab = 0.0;
3481 if (std::fabs(lambda_a - lambda_b) > 1.0e-12)
3482 v_ab = (std::fmin(lambda_a, 0.0) - std::fmin(lambda_b, 0.0)) /
3483 (lambda_a - lambda_b);
3484 else
3485 v_ab = 0.5 * (heaviside_function(-lambda_a) +
3486 heaviside_function(-lambda_b));
3487
3488 negative_projector += 0.5 * v_ab * 0.5 * (G[a][b] + G[b][a]);
3489 }
3490 }
3491 }
3492
3493 return positive_negative_tensors_projectors;
3494}
3495
3503template <int dim, typename Number>
3504DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
3507{
3509 for (unsigned int d = 0; d < dim; ++d)
3510 result[d][d] = t[d][d];
3511
3512 const Number half = internal::NumberType<Number>::value(0.5);
3513 for (unsigned int d = 0; d < dim; ++d)
3514 for (unsigned int e = d + 1; e < dim; ++e)
3515 result[d][e] = (t[d][e] + t[e][d]) * half;
3516 return result;
3517}
3518
3519
3520
3532template <int dim, typename Number>
3533DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
3535 symmetrize(const Tensor<4, dim, Number> &t, const bool major_symmetry)
3536{
3538
3539 const Number half = internal::NumberType<Number>::value(0.5);
3540
3541 // minor symmetry - A_{ijkl}=A_{jikl}=A_{ijlk}=A_{jilk}
3542 for (unsigned int i = 0; i < dim; ++i)
3543 for (unsigned int j = 0; j < dim; ++j)
3544 for (unsigned int k = 0; k < dim; ++k)
3545 for (unsigned int l = 0; l < dim; ++l)
3546 {
3547 if (i != j && k == l)
3548 {
3549 // A_{ijkk}=A_{jikk}
3550 result[i][j][k][k] = (t[i][j][k][k] + t[j][i][k][k]) * half;
3551 }
3552 else if (i == j && k != l)
3553 {
3554 // A_{iikl}=A_{iilk}
3555 result[i][i][k][l] = (t[i][i][k][l] + t[i][i][l][k]) * half;
3556 }
3557 else if (i != j && k != l)
3558 {
3559 // A_{ijkl}=A_{jilk}
3560 result[i][j][k][l] = (t[i][j][k][l] + t[j][i][k][l] +
3561 t[i][j][l][k] + t[j][i][l][k]) *
3562 half * half;
3563 }
3564 else
3565 {
3566 // A_{iijj} and A_{iiii} unchanged
3567 result[i][j][k][l] = t[i][j][k][l];
3568 }
3569 }
3570
3571 // in case major symmetry is also required
3572 if (major_symmetry)
3573 {
3574 // major symmetry - A_{ijkl}=A_{klij}
3575 for (unsigned int i = 0; i < dim; ++i)
3576 for (unsigned int j = i; j < dim; ++j)
3577 for (unsigned int k = 0; k < dim; ++k)
3578 for (unsigned int l = k; l < dim; ++l)
3579 result[i][j][k][l] = (t[i][j][k][l] + t[k][l][i][j]) * half;
3580 }
3581 return result;
3582}
3583
3584
3585
3593template <int rank_, int dim, typename Number>
3594DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
3596 operator*(const SymmetricTensor<rank_, dim, Number> &t, const Number &factor)
3597{
3599 tt *= factor;
3600 return tt;
3601}
3602
3603
3604
3612template <int rank_, int dim, typename Number>
3614operator*(const Number &factor, const SymmetricTensor<rank_, dim, Number> &t)
3615{
3616 // simply forward to the other operator
3617 return t * factor;
3618}
3619
3620
3621
3646template <int rank_, int dim, typename Number, typename OtherNumber>
3648 rank_,
3649 dim,
3650 typename ProductType<Number,
3651 typename EnableIfScalar<OtherNumber>::type>::type>
3653 const OtherNumber &factor)
3654{
3655 // form the product. we have to convert the two factors into the final
3656 // type via explicit casts because, for awkward reasons, the C++
3657 // standard committee saw it fit to not define an
3658 // operator*(float,std::complex<double>)
3659 // (as well as with switched arguments and double<->float).
3660 using product_type = typename ProductType<Number, OtherNumber>::type;
3663 return tt;
3664}
3665
3666
3667
3675template <int rank_, int dim, typename Number, typename OtherNumber>
3677 rank_,
3678 dim,
3679 typename ProductType<OtherNumber,
3680 typename EnableIfScalar<Number>::type>::type>
3681operator*(const Number &factor,
3683{
3684 // simply forward to the other operator with switched arguments
3685 return (t * factor);
3686}
3687
3688
3689
3695template <int rank_, int dim, typename Number, typename OtherNumber>
3696DEAL_II_HOST constexpr inline SymmetricTensor<
3697 rank_,
3698 dim,
3699 typename ProductType<Number,
3700 typename EnableIfScalar<OtherNumber>::type>::type>
3702 const OtherNumber &factor)
3703{
3704 using product_type = typename ProductType<Number, OtherNumber>::type;
3707 return tt;
3708}
3709
3710
3711
3718template <int rank_, int dim>
3720operator*(const SymmetricTensor<rank_, dim> &t, const double factor)
3721{
3723 tt *= factor;
3724 return tt;
3725}
3726
3727
3728
3735template <int rank_, int dim>
3737operator*(const double factor, const SymmetricTensor<rank_, dim> &t)
3738{
3740 tt *= factor;
3741 return tt;
3742}
3743
3744
3745
3751template <int rank_, int dim>
3753operator/(const SymmetricTensor<rank_, dim> &t, const double factor)
3754{
3756 tt /= factor;
3757 return tt;
3758}
3759
3769template <int dim, typename Number, typename OtherNumber>
3774{
3775 return (t1 * t2);
3776}
3777
3778
3791template <int dim, typename Number, typename OtherNumber>
3792DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE
3796{
3799 for (unsigned int i = 0; i < dim; ++i)
3800 for (unsigned int j = 0; j < dim; ++j)
3801 s += t1[i][j] * t2[i][j];
3802 return s;
3803}
3804
3805
3818template <int dim, typename Number, typename OtherNumber>
3823{
3824 return scalar_product(t2, t1);
3825}
3826
3827
3842template <typename Number, typename OtherNumber>
3843DEAL_II_HOST constexpr inline DEAL_II_ALWAYS_INLINE void
3848{
3849 tmp[0][0] = t[0][0][0][0] * s[0][0];
3850}
3851
3852
3853
3868template <typename Number, typename OtherNumber>
3869DEAL_II_HOST constexpr inline void
3874{
3875 tmp[0][0] = t[0][0][0][0] * s[0][0];
3876}
3877
3878
3879
3894template <typename Number, typename OtherNumber>
3895DEAL_II_HOST constexpr inline void
3900{
3901 const unsigned int dim = 2;
3902
3903 for (unsigned int i = 0; i < dim; ++i)
3904 for (unsigned int j = i; j < dim; ++j)
3905 tmp[i][j] = t[i][j][0][0] * s[0][0] + t[i][j][1][1] * s[1][1] +
3906 2 * t[i][j][0][1] * s[0][1];
3907}
3908
3909
3910
3925template <typename Number, typename OtherNumber>
3926DEAL_II_HOST constexpr inline void
3931{
3932 const unsigned int dim = 2;
3933
3934 for (unsigned int i = 0; i < dim; ++i)
3935 for (unsigned int j = i; j < dim; ++j)
3936 tmp[i][j] = s[0][0] * t[0][0][i][j] * +s[1][1] * t[1][1][i][j] +
3937 2 * s[0][1] * t[0][1][i][j];
3938}
3939
3940
3941
3956template <typename Number, typename OtherNumber>
3957DEAL_II_HOST constexpr inline void
3962{
3963 const unsigned int dim = 3;
3964
3965 for (unsigned int i = 0; i < dim; ++i)
3966 for (unsigned int j = i; j < dim; ++j)
3967 tmp[i][j] = t[i][j][0][0] * s[0][0] + t[i][j][1][1] * s[1][1] +
3968 t[i][j][2][2] * s[2][2] + 2 * t[i][j][0][1] * s[0][1] +
3969 2 * t[i][j][0][2] * s[0][2] + 2 * t[i][j][1][2] * s[1][2];
3970}
3971
3972
3973
3988template <typename Number, typename OtherNumber>
3989DEAL_II_HOST constexpr inline void
3994{
3995 const unsigned int dim = 3;
3996
3997 for (unsigned int i = 0; i < dim; ++i)
3998 for (unsigned int j = i; j < dim; ++j)
3999 tmp[i][j] = s[0][0] * t[0][0][i][j] + s[1][1] * t[1][1][i][j] +
4000 s[2][2] * t[2][2][i][j] + 2 * s[0][1] * t[0][1][i][j] +
4001 2 * s[0][2] * t[0][2][i][j] + 2 * s[1][2] * t[1][2][i][j];
4002}
4003
4004
4005
4012template <int dim, typename Number, typename OtherNumber>
4013DEAL_II_HOST constexpr Tensor<1,
4014 dim,
4017 const Tensor<1, dim, OtherNumber> &src2)
4018{
4020 for (unsigned int i = 0; i < dim; ++i)
4021 {
4022 dest[i] = src1[i][0] * src2[0];
4023 for (unsigned int j = 1; j < dim; ++j)
4024 dest[i] += src1[i][j] * src2[j];
4025 }
4026 return dest;
4027}
4028
4029
4036template <int dim, typename Number, typename OtherNumber>
4037DEAL_II_HOST constexpr Tensor<1,
4038 dim,
4042{
4043 // this is easy for symmetric tensors:
4044 return src2 * src1;
4045}
4046
4047
4048
4068template <int rank_1,
4069 int rank_2,
4070 int dim,
4071 typename Number,
4072 typename OtherNumber>
4074 typename Tensor<rank_1 + rank_2 - 2,
4075 dim,
4076 typename ProductType<Number, OtherNumber>::type>::tensor_type
4082
4083
4084
4104template <int rank_1,
4105 int rank_2,
4106 int dim,
4107 typename Number,
4108 typename OtherNumber>
4110 typename Tensor<rank_1 + rank_2 - 2,
4111 dim,
4112 typename ProductType<Number, OtherNumber>::type>::tensor_type
4115{
4116 return Tensor<rank_1, dim, Number>(src1) * src2;
4117}
4118
4119
4120
4130template <int dim, typename Number>
4131inline std::ostream &
4132operator<<(std::ostream &out, const SymmetricTensor<2, dim, Number> &t)
4133{
4134 // make our lives a bit simpler by outputting
4135 // the tensor through the operator for the
4136 // general Tensor class
4138
4139 for (unsigned int i = 0; i < dim; ++i)
4140 for (unsigned int j = 0; j < dim; ++j)
4141 tt[i][j] = t[i][j];
4142
4143 return out << tt;
4144}
4145
4146
4147
4157template <int dim, typename Number>
4158inline std::ostream &
4159operator<<(std::ostream &out, const SymmetricTensor<4, dim, Number> &t)
4160{
4161 // make our lives a bit simpler by outputting
4162 // the tensor through the operator for the
4163 // general Tensor class
4165
4166 for (unsigned int i = 0; i < dim; ++i)
4167 for (unsigned int j = 0; j < dim; ++j)
4168 for (unsigned int k = 0; k < dim; ++k)
4169 for (unsigned int l = 0; l < dim; ++l)
4170 tt[i][j][k][l] = t[i][j][k][l];
4171
4172 return out << tt;
4173}
4174
4175
4177
4178#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)
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)
internal::SymmetricTensorAccessors::StorageType< rank_, dim, std::complex< typename ProductType< T, U >::type > > base_tensor_descriptor
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)
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)
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 internal::SymmetricTensorAccessors::Accessor< rank_, dim, true, rank_ - 1, Number > operator[](const unsigned int row) const
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 Number second_invariant(const SymmetricTensor< 2, 3, Number > &t)
DEAL_II_HOST constexpr internal::SymmetricTensorAccessors::Accessor< rank_, dim, false, rank_ - 1, Number > operator[](const unsigned int row)
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)
typename AccessorTypes< rank, dim, constness, Number >::tensor_type tensor_type
typename AccessorTypes< rank, dim, constness, Number >::reference reference
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:166
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:40
#define DEAL_II_CONSTEXPR
Definition config.h:274
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:41
#define DEAL_II_HOST
Definition config.h:182
std::ostream & operator<<(std::ostream &out, const DerivativeForm< order, dim, spacedim, Number > &df)
const unsigned int DoFAccessor< structdim, dim, spacedim, level_dof_access >::dimension
#define DEAL_II_ASSERT_UNREACHABLE()
#define DEAL_II_NOT_IMPLEMENTED()
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)
const bool IsBlockVector< VectorType >::value
constexpr char N
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 unsigned int invalid_unsigned_int
Definition types.h:238
constexpr bool value_is_zero(const Number &value)
Definition numbers.h:881
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 > &)
typename internal::ProductTypeImpl< std::decay_t< T >, std::decay_t< U > >::type type
static constexpr const T & value(const T &t)
Definition numbers.h:668
SymmetricTensor< rank, dim, std::complex< typename ProductType< T, U >::type > > type
SymmetricTensor< rank, dim, std::complex< typename ProductType< T, U >::type > > type
SymmetricTensor< rank, dim, std::complex< typename ProductType< T, U >::type > > type
SymmetricTensor< rank, dim, std::complex< typename ProductType< T, U >::type > > type
Tensor< 1, n_independent_components, Number > base_tensor_type
typename ProductType< Number, OtherNumber >::type value_type
::SymmetricTensor< rank1+rank2 - 4, dim, value_type > 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:558
static constexpr real_type abs_square(const number &x)
Definition numbers.h:550
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()
constexpr ProductType< Number, OtherNumber >::type scalar_product(const Tensor< rank, dim, Number > &left, const Tensor< rank, dim, OtherNumber > &right)
Definition tensor.h:2547