Reference documentation for deal.II version 9.4.1
\(\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// Copyright (C) 2005 - 2022 by the deal.II authors
4//
5// This file is part of the deal.II library.
6//
7// The deal.II library is free software; you can use it, redistribute
8// it, and/or modify it under the terms of the GNU Lesser General
9// Public License as published by the Free Software Foundation; either
10// version 2.1 of the License, or (at your option) any later version.
11// The full text of the license can be found in the file LICENSE.md at
12// the top level directory of deal.II.
13//
14// ---------------------------------------------------------------------
15
16#ifndef dealii_symmetric_tensor_h
17#define dealii_symmetric_tensor_h
18
19
20#include <deal.II/base/config.h>
21
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
43template <int dim, typename Number = double>
46
75template <int dim, typename Number = double>
78
116template <int dim, typename Number = double>
119
120template <int dim, typename Number>
123
124template <int dim, typename Number>
127
137template <int dim2, typename Number>
138constexpr inline DEAL_II_ALWAYS_INLINE Number
140
151template <int dim, typename Number>
154
168template <int dim, typename Number>
171
172
173
174namespace internal
175{
176 // Workaround: The following 4 overloads are necessary to be able to
177 // compile the library with Apple Clang 8 and older. We should remove
178 // these overloads again when we bump the minimal required version to
179 // something later than clang-3.6 / Apple Clang 6.3.
180 template <int rank, int dim, typename T, typename U>
181 struct ProductTypeImpl<SymmetricTensor<rank, dim, T>, std::complex<U>>
182 {
183 using type =
184 SymmetricTensor<rank,
185 dim,
186 std::complex<typename ProductType<T, U>::type>>;
187 };
188
189 template <int rank, int dim, typename T, typename U>
190 struct ProductTypeImpl<SymmetricTensor<rank, dim, std::complex<T>>,
191 std::complex<U>>
192 {
193 using type =
194 SymmetricTensor<rank,
195 dim,
196 std::complex<typename ProductType<T, U>::type>>;
197 };
198
199 template <typename T, int rank, int dim, typename U>
200 struct ProductTypeImpl<std::complex<T>, SymmetricTensor<rank, dim, U>>
201 {
202 using type =
203 SymmetricTensor<rank,
204 dim,
205 std::complex<typename ProductType<T, U>::type>>;
206 };
207
208 template <int rank, int dim, typename T, typename U>
209 struct ProductTypeImpl<std::complex<T>,
210 SymmetricTensor<rank, dim, std::complex<U>>>
211 {
212 using type =
213 SymmetricTensor<rank,
214 dim,
215 std::complex<typename ProductType<T, U>::type>>;
216 };
217 // end workaround
218
223 namespace SymmetricTensorImplementation
224 {
229 template <int rank, int dim, typename Number>
230 struct Inverse;
231 } // namespace SymmetricTensorImplementation
232
237 namespace SymmetricTensorAccessors
238 {
246 merge(const TableIndices<2> &previous_indices,
247 const unsigned int new_index,
248 const unsigned int position)
249 {
250 AssertIndexRange(position, 2);
251
252 if (position == 0)
253 return {new_index, numbers::invalid_unsigned_int};
254 else
255 return {previous_indices[0], new_index};
256 }
257
258
259
267 merge(const TableIndices<4> &previous_indices,
268 const unsigned int new_index,
269 const unsigned int position)
270 {
271 AssertIndexRange(position, 4);
272
273 switch (position)
274 {
275 case 0:
276 return {new_index,
280 case 1:
281 return {previous_indices[0],
282 new_index,
285 case 2:
286 return {previous_indices[0],
287 previous_indices[1],
288 new_index,
290 case 3:
291 return {previous_indices[0],
292 previous_indices[1],
293 previous_indices[2],
294 new_index};
295 default:
296 Assert(false, ExcInternalError());
297 return {};
298 }
299 }
300
301
308 template <int rank1,
309 int rank2,
310 int dim,
311 typename Number,
312 typename OtherNumber = Number>
314 {
316 using type =
317 ::SymmetricTensor<rank1 + rank2 - 4, dim, value_type>;
318 };
319
320
327 template <int dim, typename Number, typename OtherNumber>
328 struct double_contraction_result<2, 2, dim, Number, OtherNumber>
329 {
331 };
332
333
334
347 template <int rank, int dim, typename Number>
349
353 template <int dim, typename Number>
354 struct StorageType<2, dim, Number>
355 {
360 static const unsigned int n_independent_components =
361 (dim * dim + dim) / 2;
362
367 };
368
369
370
374 template <int dim, typename Number>
375 struct StorageType<4, dim, Number>
376 {
382 static const unsigned int n_rank2_components = (dim * dim + dim) / 2;
383
387 static const unsigned int n_independent_components =
388 (n_rank2_components *
390
398 };
399
400
401
406 template <int rank, int dim, bool constness, typename Number>
408
415 template <int rank, int dim, typename Number>
416 struct AccessorTypes<rank, dim, true, Number>
417 {
418 using tensor_type = const ::SymmetricTensor<rank, dim, Number>;
419
420 using reference = Number;
421 };
422
429 template <int rank, int dim, typename Number>
430 struct AccessorTypes<rank, dim, false, Number>
431 {
433
434 using reference = Number &;
435 };
436
437
470 template <int rank, int dim, bool constness, int P, typename Number>
472 {
473 public:
477 using reference =
481
482 private:
503
507 constexpr DEAL_II_ALWAYS_INLINE
508 Accessor(const Accessor &) = default;
509
510 public:
514 constexpr Accessor<rank, dim, constness, P - 1, Number>
515 operator[](const unsigned int i);
516
520 constexpr Accessor<rank, dim, constness, P - 1, Number>
521 operator[](const unsigned int i) const;
522
523 private:
529
530 // Declare some other classes as friends. Make sure to work around bugs
531 // in some compilers:
532 template <int, int, typename>
533 friend class ::SymmetricTensor;
534 template <int, int, bool, int, typename>
535 friend class Accessor;
536 friend class ::SymmetricTensor<rank, dim, Number>;
537 friend class Accessor<rank, dim, constness, P + 1, Number>;
538 };
539
540
541
549 template <int rank, int dim, bool constness, typename Number>
550 class Accessor<rank, dim, constness, 1, Number>
551 {
552 public:
556 using reference =
560
561 private:
585
589 constexpr DEAL_II_ALWAYS_INLINE
590 Accessor(const Accessor &) = default;
591
592 public:
596 constexpr reference
597 operator[](const unsigned int);
598
602 constexpr reference
603 operator[](const unsigned int) const;
604
605 private:
611
612 // Declare some other classes as friends. Make sure to work around bugs
613 // in some compilers:
614 template <int, int, typename>
615 friend class ::SymmetricTensor;
616 template <int, int, bool, int, typename>
618 friend class ::SymmetricTensor<rank, dim, Number>;
619 friend class SymmetricTensorAccessors::
620 Accessor<rank, dim, constness, 2, Number>;
621 };
622 } // namespace SymmetricTensorAccessors
623} // namespace internal
624
625
626
699template <int rank_, int dim, typename Number>
701{
702public:
703 static_assert(rank_ % 2 == 0, "A SymmetricTensor must have even rank!");
704
713 static constexpr unsigned int dimension = dim;
714
718 static const unsigned int rank = rank_;
719
725 static constexpr unsigned int n_independent_components =
727 n_independent_components;
728
732 constexpr DEAL_II_ALWAYS_INLINE
733 SymmetricTensor() = default;
734
748 template <typename OtherNumber>
750
766 constexpr SymmetricTensor(const Number (&array)[n_independent_components]);
767
773 template <typename OtherNumber>
774 constexpr explicit SymmetricTensor(
776
785 DEAL_II_DEPRECATED_EARLY
786 Number *
788
797 DEAL_II_DEPRECATED_EARLY
798 const Number *
799 begin_raw() const;
800
809 DEAL_II_DEPRECATED_EARLY
810 Number *
812
822 DEAL_II_DEPRECATED_EARLY
823 const Number *
824 end_raw() const;
825
832 template <typename OtherNumber>
833 constexpr SymmetricTensor &
835
842 constexpr SymmetricTensor &
843 operator=(const Number &d);
844
849 constexpr operator Tensor<rank_, dim, Number>() const;
850
854 constexpr bool
856
860 constexpr bool
862
866 template <typename OtherNumber>
867 constexpr SymmetricTensor &
869
873 template <typename OtherNumber>
874 constexpr SymmetricTensor &
876
881 template <typename OtherNumber>
882 constexpr SymmetricTensor &
883 operator*=(const OtherNumber &factor);
884
888 template <typename OtherNumber>
889 constexpr SymmetricTensor &
890 operator/=(const OtherNumber &factor);
891
895 constexpr SymmetricTensor
896 operator-() const;
897
950 template <typename OtherNumber>
951 DEAL_II_CONSTEXPR typename internal::SymmetricTensorAccessors::
952 double_contraction_result<rank_, 2, dim, Number, OtherNumber>::type
954
959 template <typename OtherNumber>
960 DEAL_II_CONSTEXPR typename internal::SymmetricTensorAccessors::
961 double_contraction_result<rank_, 4, dim, Number, OtherNumber>::type
963
967 constexpr Number &
969
973 constexpr const Number &
974 operator()(const TableIndices<rank_> &indices) const;
975
980 constexpr internal::SymmetricTensorAccessors::
981 Accessor<rank_, dim, true, rank_ - 1, Number>
982 operator[](const unsigned int row) const;
983
988 constexpr internal::SymmetricTensorAccessors::
989 Accessor<rank_, dim, false, rank_ - 1, Number>
990 operator[](const unsigned int row);
991
997 constexpr const Number &
998 operator[](const TableIndices<rank_> &indices) const;
999
1005 constexpr Number &
1007
1014 constexpr const Number &
1015 access_raw_entry(const unsigned int unrolled_index) const;
1016
1023 constexpr Number &
1024 access_raw_entry(const unsigned int unrolled_index);
1025
1036 norm() const;
1037
1045 static constexpr unsigned int
1047
1053 static constexpr TableIndices<rank_>
1054 unrolled_to_component_indices(const unsigned int i);
1055
1068 constexpr void
1070
1075 static constexpr std::size_t
1077
1083 template <class Archive>
1084 void
1085 serialize(Archive &ar, const unsigned int version);
1086
1087private:
1093
1097 using base_tensor_type = typename base_tensor_descriptor::base_tensor_type;
1098
1103
1104#ifndef DOXYGEN
1105
1106 // Make all other symmetric tensors friends.
1107 template <int, int, typename>
1108 friend class SymmetricTensor;
1109
1110 // Make a few more functions friends.
1111 template <int dim2, typename Number2>
1112 friend constexpr Number2
1114
1115 template <int dim2, typename Number2>
1116 friend DEAL_II_CONSTEXPR Number2
1118
1119 template <int dim2, typename Number2>
1120 friend constexpr SymmetricTensor<2, dim2, Number2>
1122
1123 template <int dim2, typename Number2>
1126
1127 template <int dim2, typename Number2>
1130
1131 template <int dim2, typename Number2>
1134
1135
1136 // Make a few helper classes friends as well.
1138 Inverse<2, dim, Number>;
1139
1141 Inverse<4, dim, Number>;
1142#endif
1143};
1144
1145
1146
1147// ------------------------- inline functions ------------------------
1148
1149#ifndef DOXYGEN
1150
1151// provide declarations for static members
1152template <int rank, int dim, typename Number>
1153const unsigned int SymmetricTensor<rank, dim, Number>::dimension;
1154
1155template <int rank_, int dim, typename Number>
1156constexpr unsigned int
1157 SymmetricTensor<rank_, dim, Number>::n_independent_components;
1158
1159namespace internal
1160{
1161 namespace SymmetricTensorAccessors
1162 {
1163 template <int rank_, int dim, bool constness, int P, typename Number>
1164 constexpr DEAL_II_ALWAYS_INLINE
1165 Accessor<rank_, dim, constness, P, Number>::Accessor(
1166 tensor_type & tensor,
1167 const TableIndices<rank_> &previous_indices)
1168 : tensor(tensor)
1169 , previous_indices(previous_indices)
1170 {}
1171
1172
1173
1174 template <int rank_, int dim, bool constness, int P, typename Number>
1175 constexpr inline DEAL_II_ALWAYS_INLINE
1176 Accessor<rank_, dim, constness, P - 1, Number>
1177 Accessor<rank_, dim, constness, P, Number>::operator[](
1178 const unsigned int i)
1179 {
1180 return Accessor<rank_, dim, constness, P - 1, Number>(
1181 tensor, merge(previous_indices, i, rank_ - P));
1182 }
1183
1184
1185
1186 template <int rank_, int dim, bool constness, int P, typename Number>
1187 constexpr DEAL_II_ALWAYS_INLINE
1188 Accessor<rank_, dim, constness, P - 1, Number>
1189 Accessor<rank_, dim, constness, P, Number>::operator[](
1190 const unsigned int i) const
1191 {
1192 return Accessor<rank_, dim, constness, P - 1, Number>(
1193 tensor, merge(previous_indices, i, rank_ - P));
1194 }
1195
1196
1197
1198 template <int rank_, int dim, bool constness, typename Number>
1199 constexpr DEAL_II_ALWAYS_INLINE
1200 Accessor<rank_, dim, constness, 1, Number>::Accessor(
1201 tensor_type & tensor,
1202 const TableIndices<rank_> &previous_indices)
1203 : tensor(tensor)
1204 , previous_indices(previous_indices)
1205 {}
1206
1207
1208
1209 template <int rank_, int dim, bool constness, typename Number>
1210 constexpr inline DEAL_II_ALWAYS_INLINE
1211 typename Accessor<rank_, dim, constness, 1, Number>::reference
1212 Accessor<rank_, dim, constness, 1, Number>::operator[](
1213 const unsigned int i)
1214 {
1215 return tensor(merge(previous_indices, i, rank_ - 1));
1216 }
1217
1218
1219 template <int rank_, int dim, bool constness, typename Number>
1220 constexpr DEAL_II_ALWAYS_INLINE
1221 typename Accessor<rank_, dim, constness, 1, Number>::reference
1222 Accessor<rank_, dim, constness, 1, Number>::operator[](
1223 const unsigned int i) const
1224 {
1225 return tensor(merge(previous_indices, i, rank_ - 1));
1226 }
1227 } // namespace SymmetricTensorAccessors
1228} // namespace internal
1229
1230
1231
1232template <int rank_, int dim, typename Number>
1233template <typename OtherNumber>
1237{
1238 static_assert(rank == 2, "This function is only implemented for rank==2");
1239 for (unsigned int d = 0; d < dim; ++d)
1240 for (unsigned int e = 0; e < d; ++e)
1241 Assert(t[d][e] == t[e][d],
1242 ExcMessage("The incoming Tensor must be exactly symmetric."));
1243
1244 for (unsigned int d = 0; d < dim; ++d)
1245 data[d] = t[d][d];
1246
1247 for (unsigned int d = 0, c = 0; d < dim; ++d)
1248 for (unsigned int e = d + 1; e < dim; ++e, ++c)
1249 data[dim + c] = t[d][e];
1250}
1251
1252
1253
1254template <int rank_, int dim, typename Number>
1255template <typename OtherNumber>
1256constexpr DEAL_II_ALWAYS_INLINE
1259 : data(initializer.data)
1260{}
1261
1262
1263
1264template <int rank_, int dim, typename Number>
1265constexpr inline DEAL_II_ALWAYS_INLINE
1267 const Number (&array)[n_independent_components])
1268 : data(
1269 *reinterpret_cast<const typename base_tensor_type::array_type *>(array))
1270{
1271 // ensure that the reinterpret_cast above actually works
1272 Assert(sizeof(typename base_tensor_type::array_type) == sizeof(array),
1274}
1275
1276
1277
1278template <int rank_, int dim, typename Number>
1279template <typename OtherNumber>
1283{
1284 data = t.data;
1285 return *this;
1286}
1287
1288
1289
1290template <int rank_, int dim, typename Number>
1293{
1295 ExcMessage("Only assignment with zero is allowed"));
1296 (void)d;
1297
1299
1300 return *this;
1301}
1302
1303
1304namespace internal
1305{
1306 namespace SymmetricTensorImplementation
1307 {
1308 template <int dim, typename Number>
1309 constexpr inline DEAL_II_ALWAYS_INLINE ::Tensor<2, dim, Number>
1310 convert_to_tensor(const ::SymmetricTensor<2, dim, Number> &s)
1311 {
1313
1314 // diagonal entries are stored first
1315 for (unsigned int d = 0; d < dim; ++d)
1316 t[d][d] = s.access_raw_entry(d);
1317
1318 // off-diagonal entries come next, row by row
1319 for (unsigned int d = 0, c = 0; d < dim; ++d)
1320 for (unsigned int e = d + 1; e < dim; ++e, ++c)
1321 {
1322 t[d][e] = s.access_raw_entry(dim + c);
1323 t[e][d] = s.access_raw_entry(dim + c);
1324 }
1325 return t;
1326 }
1327
1328
1329 template <int dim, typename Number>
1330 constexpr ::Tensor<4, dim, Number>
1331 convert_to_tensor(const ::SymmetricTensor<4, dim, Number> &st)
1332 {
1333 // utilize the symmetry properties of SymmetricTensor<4,dim>
1334 // discussed in the class documentation to avoid accessing all
1335 // independent elements of the input tensor more than once
1337
1338 for (unsigned int i = 0; i < dim; ++i)
1339 for (unsigned int j = i; j < dim; ++j)
1340 for (unsigned int k = 0; k < dim; ++k)
1341 for (unsigned int l = k; l < dim; ++l)
1342 t[TableIndices<4>(i, j, k, l)] = t[TableIndices<4>(i, j, l, k)] =
1343 t[TableIndices<4>(j, i, k, l)] =
1344 t[TableIndices<4>(j, i, l, k)] =
1345 st[TableIndices<4>(i, j, k, l)];
1346
1347 return t;
1348 }
1349
1350
1351 template <typename Number>
1352 struct Inverse<2, 1, Number>
1353 {
1354 constexpr static inline DEAL_II_ALWAYS_INLINE
1355 ::SymmetricTensor<2, 1, Number>
1356 value(const ::SymmetricTensor<2, 1, Number> &t)
1357 {
1359
1360 tmp[0][0] = 1.0 / t[0][0];
1361
1362 return tmp;
1363 }
1364 };
1365
1366
1367 template <typename Number>
1368 struct Inverse<2, 2, Number>
1369 {
1370 constexpr static inline DEAL_II_ALWAYS_INLINE
1371 ::SymmetricTensor<2, 2, Number>
1372 value(const ::SymmetricTensor<2, 2, Number> &t)
1373 {
1375
1376 // Sympy result: ([
1377 // [ t11/(t00*t11 - t01**2), -t01/(t00*t11 - t01**2)],
1378 // [-t01/(t00*t11 - t01**2), t00/(t00*t11 - t01**2)] ])
1379 const TableIndices<2> idx_00(0, 0);
1380 const TableIndices<2> idx_01(0, 1);
1381 const TableIndices<2> idx_11(1, 1);
1382 const Number inv_det_t =
1383 1.0 / (t[idx_00] * t[idx_11] - t[idx_01] * t[idx_01]);
1384 tmp[idx_00] = t[idx_11];
1385 tmp[idx_01] = -t[idx_01];
1386 tmp[idx_11] = t[idx_00];
1387 tmp *= inv_det_t;
1388
1389 return tmp;
1390 }
1391 };
1392
1393
1394 template <typename Number>
1395 struct Inverse<2, 3, Number>
1396 {
1397 constexpr static ::SymmetricTensor<2, 3, Number>
1398 value(const ::SymmetricTensor<2, 3, Number> &t)
1399 {
1401
1402 // Sympy result: ([
1403 // [ (t11*t22 - t12**2)/(t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1404 // 2*t01*t02*t12 - t02**2*t11),
1405 // (-t01*t22 + t02*t12)/(t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1406 // 2*t01*t02*t12 - t02**2*t11),
1407 // (t01*t12 - t02*t11)/(t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1408 // 2*t01*t02*t12 - t02**2*t11)],
1409 // [ (-t01*t22 + t02*t12)/(t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1410 // 2*t01*t02*t12 - t02**2*t11),
1411 // (t00*t22 - t02**2)/(t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1412 // 2*t01*t02*t12 - t02**2*t11),
1413 // (t00*t12 - t01*t02)/(-t00*t11*t22 + t00*t12**2 + t01**2*t22 -
1414 // 2*t01*t02*t12 + t02**2*t11)],
1415 // [ (t01*t12 - t02*t11)/(t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1416 // 2*t01*t02*t12 - t02**2*t11),
1417 // (t00*t12 - t01*t02)/(-t00*t11*t22 + t00*t12**2 + t01**2*t22 -
1418 // 2*t01*t02*t12 + t02**2*t11),
1419 // (-t00*t11 + t01**2)/(-t00*t11*t22 + t00*t12**2 + t01**2*t22 -
1420 // 2*t01*t02*t12 + t02**2*t11)] ])
1421 //
1422 // =
1423 //
1424 // [ (t11*t22 - t12**2)/det_t,
1425 // (-t01*t22 + t02*t12)/det_t,
1426 // (t01*t12 - t02*t11)/det_t],
1427 // [ (-t01*t22 + t02*t12)/det_t,
1428 // (t00*t22 - t02**2)/det_t,
1429 // (-t00*t12 + t01*t02)/det_t],
1430 // [ (t01*t12 - t02*t11)/det_t,
1431 // (-t00*t12 + t01*t02)/det_t,
1432 // (t00*t11 - t01**2)/det_t] ])
1433 //
1434 // with det_t = (t00*t11*t22 - t00*t12**2 - t01**2*t22 +
1435 // 2*t01*t02*t12 - t02**2*t11)
1436 const TableIndices<2> idx_00(0, 0);
1437 const TableIndices<2> idx_01(0, 1);
1438 const TableIndices<2> idx_02(0, 2);
1439 const TableIndices<2> idx_11(1, 1);
1440 const TableIndices<2> idx_12(1, 2);
1441 const TableIndices<2> idx_22(2, 2);
1442 const Number inv_det_t =
1443 1.0 / (t[idx_00] * t[idx_11] * t[idx_22] -
1444 t[idx_00] * t[idx_12] * t[idx_12] -
1445 t[idx_01] * t[idx_01] * t[idx_22] +
1446 2.0 * t[idx_01] * t[idx_02] * t[idx_12] -
1447 t[idx_02] * t[idx_02] * t[idx_11]);
1448 tmp[idx_00] = t[idx_11] * t[idx_22] - t[idx_12] * t[idx_12];
1449 tmp[idx_01] = -t[idx_01] * t[idx_22] + t[idx_02] * t[idx_12];
1450 tmp[idx_02] = t[idx_01] * t[idx_12] - t[idx_02] * t[idx_11];
1451 tmp[idx_11] = t[idx_00] * t[idx_22] - t[idx_02] * t[idx_02];
1452 tmp[idx_12] = -t[idx_00] * t[idx_12] + t[idx_01] * t[idx_02];
1453 tmp[idx_22] = t[idx_00] * t[idx_11] - t[idx_01] * t[idx_01];
1454 tmp *= inv_det_t;
1455
1456 return tmp;
1457 }
1458 };
1459
1460
1461 template <typename Number>
1462 struct Inverse<4, 1, Number>
1463 {
1464 constexpr static inline ::SymmetricTensor<4, 1, Number>
1465 value(const ::SymmetricTensor<4, 1, Number> &t)
1466 {
1468 tmp.data[0][0] = 1.0 / t.data[0][0];
1469 return tmp;
1470 }
1471 };
1472
1473
1474 template <typename Number>
1475 struct Inverse<4, 2, Number>
1476 {
1477 constexpr static inline ::SymmetricTensor<4, 2, Number>
1478 value(const ::SymmetricTensor<4, 2, Number> &t)
1479 {
1481
1482 // Inverting this tensor is a little more complicated than necessary,
1483 // since we store the data of 't' as a 3x3 matrix t.data, but the
1484 // product between a rank-4 and a rank-2 tensor is really not the
1485 // product between this matrix and the 3-vector of a rhs, but rather
1486 //
1487 // B.vec = t.data * mult * A.vec
1488 //
1489 // where mult is a 3x3 matrix with entries [[1,0,0],[0,1,0],[0,0,2]] to
1490 // capture the fact that we need to add up both the c_ij12*a_12 and the
1491 // c_ij21*a_21 terms.
1492 //
1493 // In addition, in this scheme, the identity tensor has the matrix
1494 // representation mult^-1.
1495 //
1496 // The inverse of 't' therefore has the matrix representation
1497 //
1498 // inv.data = mult^-1 * t.data^-1 * mult^-1
1499 //
1500 // in order to compute it, let's first compute the inverse of t.data and
1501 // put it into tmp.data; at the end of the function we then scale the
1502 // last row and column of the inverse by 1/2, corresponding to the left
1503 // and right multiplication with mult^-1.
1504 const Number t4 = t.data[0][0] * t.data[1][1],
1505 t6 = t.data[0][0] * t.data[1][2],
1506 t8 = t.data[0][1] * t.data[1][0],
1507 t00 = t.data[0][2] * t.data[1][0],
1508 t01 = t.data[0][1] * t.data[2][0],
1509 t04 = t.data[0][2] * t.data[2][0],
1510 t07 = 1.0 / (t4 * t.data[2][2] - t6 * t.data[2][1] -
1511 t8 * t.data[2][2] + t00 * t.data[2][1] +
1512 t01 * t.data[1][2] - t04 * t.data[1][1]);
1513 tmp.data[0][0] =
1514 (t.data[1][1] * t.data[2][2] - t.data[1][2] * t.data[2][1]) * t07;
1515 tmp.data[0][1] =
1516 -(t.data[0][1] * t.data[2][2] - t.data[0][2] * t.data[2][1]) * t07;
1517 tmp.data[0][2] =
1518 -(-t.data[0][1] * t.data[1][2] + t.data[0][2] * t.data[1][1]) * t07;
1519 tmp.data[1][0] =
1520 -(t.data[1][0] * t.data[2][2] - t.data[1][2] * t.data[2][0]) * t07;
1521 tmp.data[1][1] = (t.data[0][0] * t.data[2][2] - t04) * t07;
1522 tmp.data[1][2] = -(t6 - t00) * t07;
1523 tmp.data[2][0] =
1524 -(-t.data[1][0] * t.data[2][1] + t.data[1][1] * t.data[2][0]) * t07;
1525 tmp.data[2][1] = -(t.data[0][0] * t.data[2][1] - t01) * t07;
1526 tmp.data[2][2] = (t4 - t8) * t07;
1527
1528 // scale last row and column as mentioned
1529 // above
1530 tmp.data[2][0] /= 2;
1531 tmp.data[2][1] /= 2;
1532 tmp.data[0][2] /= 2;
1533 tmp.data[1][2] /= 2;
1534 tmp.data[2][2] /= 4;
1535
1536 return tmp;
1537 }
1538 };
1539
1540
1541 template <typename Number>
1542 struct Inverse<4, 3, Number>
1543 {
1544 static ::SymmetricTensor<4, 3, Number>
1545 value(const ::SymmetricTensor<4, 3, Number> &t)
1546 {
1548
1549 // This function follows the exact same scheme as the 2d case, except
1550 // that hardcoding the inverse of a 6x6 matrix is pretty wasteful.
1551 // Instead, we use the Gauss-Jordan algorithm implemented for
1552 // FullMatrix. For historical reasons the following code is copied from
1553 // there, with the tangential benefit that we do not need to copy the
1554 // tensor entries to and from the FullMatrix.
1555 const unsigned int N = 6;
1556
1557 // First get an estimate of the size of the elements of this matrix,
1558 // for later checks whether the pivot element is large enough, or
1559 // whether we have to fear that the matrix is not regular.
1560 Number diagonal_sum = internal::NumberType<Number>::value(0.0);
1561 for (unsigned int i = 0; i < N; ++i)
1562 diagonal_sum += std::fabs(tmp.data[i][i]);
1563 const Number typical_diagonal_element =
1564 diagonal_sum / static_cast<double>(N);
1565 (void)typical_diagonal_element;
1566
1567 unsigned int p[N];
1568 for (unsigned int i = 0; i < N; ++i)
1569 p[i] = i;
1570
1571 for (unsigned int j = 0; j < N; ++j)
1572 {
1573 // Pivot search: search that part of the line on and right of the
1574 // diagonal for the largest element.
1575 Number max = std::fabs(tmp.data[j][j]);
1576 unsigned int r = j;
1577 for (unsigned int i = j + 1; i < N; ++i)
1578 if (std::fabs(tmp.data[i][j]) > max)
1579 {
1580 max = std::fabs(tmp.data[i][j]);
1581 r = i;
1582 }
1583
1584 // Check whether the pivot is too small
1585 Assert(max > 1.e-16 * typical_diagonal_element,
1586 ExcMessage("This tensor seems to be noninvertible"));
1587
1588 // Row interchange
1589 if (r > j)
1590 {
1591 for (unsigned int k = 0; k < N; ++k)
1592 std::swap(tmp.data[j][k], tmp.data[r][k]);
1593
1594 std::swap(p[j], p[r]);
1595 }
1596
1597 // Transformation
1598 const Number hr = 1. / tmp.data[j][j];
1599 tmp.data[j][j] = hr;
1600 for (unsigned int k = 0; k < N; ++k)
1601 {
1602 if (k == j)
1603 continue;
1604 for (unsigned int i = 0; i < N; ++i)
1605 {
1606 if (i == j)
1607 continue;
1608 tmp.data[i][k] -= tmp.data[i][j] * tmp.data[j][k] * hr;
1609 }
1610 }
1611 for (unsigned int i = 0; i < N; ++i)
1612 {
1613 tmp.data[i][j] *= hr;
1614 tmp.data[j][i] *= -hr;
1615 }
1616 tmp.data[j][j] = hr;
1617 }
1618
1619 // Column interchange
1620 Number hv[N];
1621 for (unsigned int i = 0; i < N; ++i)
1622 {
1623 for (unsigned int k = 0; k < N; ++k)
1624 hv[p[k]] = tmp.data[i][k];
1625 for (unsigned int k = 0; k < N; ++k)
1626 tmp.data[i][k] = hv[k];
1627 }
1628
1629 // Scale rows and columns. The mult matrix
1630 // here is diag[1, 1, 1, 1/2, 1/2, 1/2].
1631 for (unsigned int i = 3; i < 6; ++i)
1632 for (unsigned int j = 0; j < 3; ++j)
1633 tmp.data[i][j] /= 2;
1634
1635 for (unsigned int i = 0; i < 3; ++i)
1636 for (unsigned int j = 3; j < 6; ++j)
1637 tmp.data[i][j] /= 2;
1638
1639 for (unsigned int i = 3; i < 6; ++i)
1640 for (unsigned int j = 3; j < 6; ++j)
1641 tmp.data[i][j] /= 4;
1642
1643 return tmp;
1644 }
1645 };
1646
1647 } // namespace SymmetricTensorImplementation
1648} // namespace internal
1649
1650
1651
1652template <int rank_, int dim, typename Number>
1653constexpr DEAL_II_ALWAYS_INLINE
1655 const
1656{
1657 return internal::SymmetricTensorImplementation::convert_to_tensor(*this);
1658}
1659
1660
1661
1662template <int rank_, int dim, typename Number>
1663constexpr bool
1666{
1667 return data == t.data;
1668}
1669
1670
1671
1672template <int rank_, int dim, typename Number>
1673constexpr bool
1676{
1677 return data != t.data;
1678}
1679
1680
1681
1682template <int rank_, int dim, typename Number>
1683template <typename OtherNumber>
1687{
1688 data += t.data;
1689 return *this;
1690}
1691
1692
1693
1694template <int rank_, int dim, typename Number>
1695template <typename OtherNumber>
1699{
1700 data -= t.data;
1701 return *this;
1702}
1703
1704
1705
1706template <int rank_, int dim, typename Number>
1707template <typename OtherNumber>
1710{
1711 data *= d;
1712 return *this;
1713}
1714
1715
1716
1717template <int rank_, int dim, typename Number>
1718template <typename OtherNumber>
1721{
1722 data /= d;
1723 return *this;
1724}
1725
1726
1727
1728template <int rank_, int dim, typename Number>
1731{
1732 SymmetricTensor tmp = *this;
1733 tmp.data = -tmp.data;
1734 return tmp;
1735}
1736
1737
1738
1739template <int rank_, int dim, typename Number>
1740constexpr inline DEAL_II_ALWAYS_INLINE void
1742{
1743 data.clear();
1744}
1745
1746
1747
1748template <int rank_, int dim, typename Number>
1749constexpr std::size_t
1751{
1752 // all memory consists of statically allocated memory of the current
1753 // object, no pointers
1755}
1756
1757
1758
1759namespace internal
1760{
1761 template <int dim, typename Number, typename OtherNumber = Number>
1763 typename SymmetricTensorAccessors::
1764 double_contraction_result<2, 2, dim, Number, OtherNumber>::type
1765 perform_double_contraction(
1766 const typename SymmetricTensorAccessors::StorageType<2, dim, Number>::
1767 base_tensor_type &data,
1768 const typename SymmetricTensorAccessors::
1769 StorageType<2, dim, OtherNumber>::base_tensor_type &sdata)
1770 {
1771 using result_type = typename SymmetricTensorAccessors::
1772 double_contraction_result<2, 2, dim, Number, OtherNumber>::type;
1773
1774 switch (dim)
1775 {
1776 case 1:
1777 return data[0] * sdata[0];
1778 default:
1779 // Start with the non-diagonal part to avoid some multiplications by
1780 // 2.
1781
1782 result_type sum = data[dim] * sdata[dim];
1783 for (unsigned int d = dim + 1; d < (dim * (dim + 1) / 2); ++d)
1784 sum += data[d] * sdata[d];
1785 sum += sum; // sum = sum * 2.;
1786
1787 // Now add the contributions from the diagonal
1788 for (unsigned int d = 0; d < dim; ++d)
1789 sum += data[d] * sdata[d];
1790 return sum;
1791 }
1792 }
1793
1794
1795
1796 template <int dim, typename Number, typename OtherNumber = Number>
1798 typename SymmetricTensorAccessors::
1799 double_contraction_result<4, 2, dim, Number, OtherNumber>::type
1800 perform_double_contraction(
1801 const typename SymmetricTensorAccessors::StorageType<4, dim, Number>::
1802 base_tensor_type &data,
1803 const typename SymmetricTensorAccessors::
1804 StorageType<2, dim, OtherNumber>::base_tensor_type &sdata)
1805 {
1806 using result_type = typename SymmetricTensorAccessors::
1807 double_contraction_result<4, 2, dim, Number, OtherNumber>::type;
1808 using value_type = typename SymmetricTensorAccessors::
1809 double_contraction_result<4, 2, dim, Number, OtherNumber>::value_type;
1810
1811 const unsigned int data_dim = SymmetricTensorAccessors::
1812 StorageType<2, dim, value_type>::n_independent_components;
1813 value_type tmp[data_dim]{};
1814 for (unsigned int i = 0; i < data_dim; ++i)
1815 tmp[i] =
1816 perform_double_contraction<dim, Number, OtherNumber>(data[i], sdata);
1817 return result_type(tmp);
1818 }
1819
1820
1821
1822 template <int dim, typename Number, typename OtherNumber = Number>
1824 typename SymmetricTensorAccessors::StorageType<
1825 2,
1826 dim,
1827 typename SymmetricTensorAccessors::
1828 double_contraction_result<2, 4, dim, Number, OtherNumber>::value_type>::
1829 base_tensor_type
1830 perform_double_contraction(
1831 const typename SymmetricTensorAccessors::StorageType<2, dim, Number>::
1832 base_tensor_type &data,
1833 const typename SymmetricTensorAccessors::
1834 StorageType<4, dim, OtherNumber>::base_tensor_type &sdata)
1835 {
1836 using value_type = typename SymmetricTensorAccessors::
1837 double_contraction_result<2, 4, dim, Number, OtherNumber>::value_type;
1838 using base_tensor_type = typename SymmetricTensorAccessors::
1839 StorageType<2, dim, value_type>::base_tensor_type;
1840
1841 base_tensor_type tmp;
1842 for (unsigned int i = 0; i < tmp.dimension; ++i)
1843 {
1844 // Start with the non-diagonal part
1845 value_type sum = data[dim] * sdata[dim][i];
1846 for (unsigned int d = dim + 1; d < (dim * (dim + 1) / 2); ++d)
1847 sum += data[d] * sdata[d][i];
1848 sum += sum; // sum = sum * 2.;
1849
1850 // Now add the contributions from the diagonal
1851 for (unsigned int d = 0; d < dim; ++d)
1852 sum += data[d] * sdata[d][i];
1853 tmp[i] = sum;
1854 }
1855 return tmp;
1856 }
1857
1858
1859
1860 template <int dim, typename Number, typename OtherNumber = Number>
1862 typename SymmetricTensorAccessors::StorageType<
1863 4,
1864 dim,
1865 typename SymmetricTensorAccessors::
1866 double_contraction_result<4, 4, dim, Number, OtherNumber>::value_type>::
1867 base_tensor_type
1868 perform_double_contraction(
1869 const typename SymmetricTensorAccessors::StorageType<4, dim, Number>::
1870 base_tensor_type &data,
1871 const typename SymmetricTensorAccessors::
1872 StorageType<4, dim, OtherNumber>::base_tensor_type &sdata)
1873 {
1874 using value_type = typename SymmetricTensorAccessors::
1875 double_contraction_result<4, 4, dim, Number, OtherNumber>::value_type;
1876 using base_tensor_type = typename SymmetricTensorAccessors::
1877 StorageType<4, dim, value_type>::base_tensor_type;
1878
1879 const unsigned int data_dim = SymmetricTensorAccessors::
1880 StorageType<2, dim, value_type>::n_independent_components;
1881 base_tensor_type tmp;
1882 for (unsigned int i = 0; i < data_dim; ++i)
1883 for (unsigned int j = 0; j < data_dim; ++j)
1884 {
1885 // Start with the non-diagonal part
1886 for (unsigned int d = dim; d < (dim * (dim + 1) / 2); ++d)
1887 tmp[i][j] += data[i][d] * sdata[d][j];
1888 tmp[i][j] += tmp[i][j]; // tmp[i][j] = tmp[i][j] * 2;
1889
1890 // Now add the contributions from the diagonal
1891 for (unsigned int d = 0; d < dim; ++d)
1892 tmp[i][j] += data[i][d] * sdata[d][j];
1893 }
1894 return tmp;
1895 }
1896
1897} // end of namespace internal
1898
1899
1900
1901template <int rank_, int dim, typename Number>
1902template <typename OtherNumber>
1904 typename internal::SymmetricTensorAccessors::
1905 double_contraction_result<rank_, 2, dim, Number, OtherNumber>::type
1908{
1909 // need to have two different function calls
1910 // because a scalar and rank-2 tensor are not
1911 // the same data type (see internal function
1912 // above)
1913 return internal::perform_double_contraction<dim, Number, OtherNumber>(data,
1914 s.data);
1915}
1916
1917
1918
1919template <int rank_, int dim, typename Number>
1920template <typename OtherNumber>
1921DEAL_II_CONSTEXPR inline typename internal::SymmetricTensorAccessors::
1922 double_contraction_result<rank_, 4, dim, Number, OtherNumber>::type
1925{
1926 typename internal::SymmetricTensorAccessors::
1927 double_contraction_result<rank_, 4, dim, Number, OtherNumber>::type tmp;
1928 tmp.data =
1929 internal::perform_double_contraction<dim, Number, OtherNumber>(data,
1930 s.data);
1931 return tmp;
1932}
1933
1934
1935
1936// internal namespace to switch between the
1937// access of different tensors. There used to
1938// be explicit instantiations before for
1939// different ranks and dimensions, but since
1940// we now allow for templates on the data
1941// type, and since we cannot partially
1942// specialize the implementation, this got
1943// into a separate namespace
1944namespace internal
1945{
1946 // The variables within this struct will be referenced in the next functions.
1947 // It is a workaround that allows returning a reference to a static variable
1948 // while allowing constexpr evaluation of the function.
1949 // It has to be defined outside the function because constexpr functions
1950 // cannot define static variables.
1951 // A similar struct has also been defined in tensor.h
1952 template <typename Type>
1953 struct Uninitialized
1954 {
1955 static Type value;
1956 };
1957
1958 template <typename Type>
1959 Type Uninitialized<Type>::value;
1960
1961 template <int dim, typename Number>
1962 constexpr inline DEAL_II_ALWAYS_INLINE Number &
1963 symmetric_tensor_access(const TableIndices<2> &indices,
1964 typename SymmetricTensorAccessors::
1965 StorageType<2, dim, Number>::base_tensor_type &data)
1966 {
1967 // 1d is very simple and done first
1968 if (dim == 1)
1969 return data[0];
1970
1971 // first treat the main diagonal elements, which are stored consecutively
1972 // at the beginning
1973 if (indices[0] == indices[1])
1974 return data[indices[0]];
1975
1976 // the rest is messier and requires a few switches.
1977 switch (dim)
1978 {
1979 case 2:
1980 // at least for the 2x2 case it is reasonably simple
1981 Assert(((indices[0] == 1) && (indices[1] == 0)) ||
1982 ((indices[0] == 0) && (indices[1] == 1)),
1984 return data[2];
1985
1986 default:
1987 // to do the rest, sort our indices before comparing
1988 {
1989 TableIndices<2> sorted_indices(std::min(indices[0], indices[1]),
1990 std::max(indices[0], indices[1]));
1991 for (unsigned int d = 0, c = 0; d < dim; ++d)
1992 for (unsigned int e = d + 1; e < dim; ++e, ++c)
1993 if ((sorted_indices[0] == d) && (sorted_indices[1] == e))
1994 return data[dim + c];
1995 Assert(false, ExcInternalError());
1996 }
1997 }
1998
1999 // The code should never reach there.
2000 // Returns a dummy reference to a dummy variable just to make the
2001 // compiler happy.
2002 return Uninitialized<Number>::value;
2003 }
2004
2005
2006
2007 template <int dim, typename Number>
2008 constexpr inline DEAL_II_ALWAYS_INLINE const Number &
2009 symmetric_tensor_access(const TableIndices<2> &indices,
2010 const typename SymmetricTensorAccessors::
2011 StorageType<2, dim, Number>::base_tensor_type &data)
2012 {
2013 // 1d is very simple and done first
2014 if (dim == 1)
2015 return data[0];
2016
2017 // first treat the main diagonal elements, which are stored consecutively
2018 // at the beginning
2019 if (indices[0] == indices[1])
2020 return data[indices[0]];
2021
2022 // the rest is messier and requires a few switches.
2023 switch (dim)
2024 {
2025 case 2:
2026 // at least for the 2x2 case it is reasonably simple
2027 Assert(((indices[0] == 1) && (indices[1] == 0)) ||
2028 ((indices[0] == 0) && (indices[1] == 1)),
2030 return data[2];
2031
2032 default:
2033 // to do the rest, sort our indices before comparing
2034 {
2035 TableIndices<2> sorted_indices(std::min(indices[0], indices[1]),
2036 std::max(indices[0], indices[1]));
2037 for (unsigned int d = 0, c = 0; d < dim; ++d)
2038 for (unsigned int e = d + 1; e < dim; ++e, ++c)
2039 if ((sorted_indices[0] == d) && (sorted_indices[1] == e))
2040 return data[dim + c];
2041 Assert(false, ExcInternalError());
2042 }
2043 }
2044
2045 // The code should never reach there.
2046 // Returns a dummy reference to a dummy variable just to make the
2047 // compiler happy.
2048 return Uninitialized<Number>::value;
2049 }
2050
2051
2052
2053 template <int dim, typename Number>
2054 constexpr inline Number &
2055 symmetric_tensor_access(const TableIndices<4> &indices,
2056 typename SymmetricTensorAccessors::
2057 StorageType<4, dim, Number>::base_tensor_type &data)
2058 {
2059 switch (dim)
2060 {
2061 case 1:
2062 return data[0][0];
2063
2064 case 2:
2065 // each entry of the tensor can be thought of as an entry in a
2066 // matrix that maps the rolled-out rank-2 tensors into rolled-out
2067 // rank-2 tensors. this is the format in which we store rank-4
2068 // tensors. determine which position the present entry is
2069 // stored in
2070 {
2071 constexpr std::size_t base_index[2][2] = {{0, 2}, {2, 1}};
2072 return data[base_index[indices[0]][indices[1]]]
2073 [base_index[indices[2]][indices[3]]];
2074 }
2075 case 3:
2076 // each entry of the tensor can be thought of as an entry in a
2077 // matrix that maps the rolled-out rank-2 tensors into rolled-out
2078 // rank-2 tensors. this is the format in which we store rank-4
2079 // tensors. determine which position the present entry is
2080 // stored in
2081 {
2082 constexpr std::size_t base_index[3][3] = {{0, 3, 4},
2083 {3, 1, 5},
2084 {4, 5, 2}};
2085 return data[base_index[indices[0]][indices[1]]]
2086 [base_index[indices[2]][indices[3]]];
2087 }
2088
2089 default:
2090 Assert(false, ExcNotImplemented());
2091 }
2092
2093 // The code should never reach there.
2094 // Returns a dummy reference to a dummy variable just to make the
2095 // compiler happy.
2096 return Uninitialized<Number>::value;
2097 }
2098
2099
2100 template <int dim, typename Number>
2101 constexpr inline DEAL_II_ALWAYS_INLINE const Number &
2102 symmetric_tensor_access(const TableIndices<4> &indices,
2103 const typename SymmetricTensorAccessors::
2104 StorageType<4, dim, Number>::base_tensor_type &data)
2105 {
2106 switch (dim)
2107 {
2108 case 1:
2109 return data[0][0];
2110
2111 case 2:
2112 // each entry of the tensor can be thought of as an entry in a
2113 // matrix that maps the rolled-out rank-2 tensors into rolled-out
2114 // rank-2 tensors. this is the format in which we store rank-4
2115 // tensors. determine which position the present entry is
2116 // stored in
2117 {
2118 constexpr std::size_t base_index[2][2] = {{0, 2}, {2, 1}};
2119 return data[base_index[indices[0]][indices[1]]]
2120 [base_index[indices[2]][indices[3]]];
2121 }
2122 case 3:
2123 // each entry of the tensor can be thought of as an entry in a
2124 // matrix that maps the rolled-out rank-2 tensors into rolled-out
2125 // rank-2 tensors. this is the format in which we store rank-4
2126 // tensors. determine which position the present entry is
2127 // stored in
2128 {
2129 constexpr std::size_t base_index[3][3] = {{0, 3, 4},
2130 {3, 1, 5},
2131 {4, 5, 2}};
2132 return data[base_index[indices[0]][indices[1]]]
2133 [base_index[indices[2]][indices[3]]];
2134 }
2135
2136 default:
2137 Assert(false, ExcNotImplemented());
2138 }
2139
2140 // The code should never reach there.
2141 // Returns a dummy reference to a dummy variable just to make the
2142 // compiler happy.
2143 return Uninitialized<Number>::value;
2144 }
2145
2146} // end of namespace internal
2147
2148
2149
2150template <int rank_, int dim, typename Number>
2151constexpr inline DEAL_II_ALWAYS_INLINE Number &
2153 const TableIndices<rank_> &indices)
2154{
2155 for (unsigned int r = 0; r < rank; ++r)
2156 AssertIndexRange(indices[r], dimension);
2157 return internal::symmetric_tensor_access<dim, Number>(indices, data);
2158}
2159
2160
2161
2162template <int rank_, int dim, typename Number>
2163constexpr inline DEAL_II_ALWAYS_INLINE const Number &
2165 const TableIndices<rank_> &indices) const
2166{
2167 for (unsigned int r = 0; r < rank; ++r)
2168 AssertIndexRange(indices[r], dimension);
2169 return internal::symmetric_tensor_access<dim, Number>(indices, data);
2170}
2171
2172
2173
2174namespace internal
2175{
2176 namespace SymmetricTensorImplementation
2177 {
2178 template <int rank_>
2179 constexpr TableIndices<rank_>
2180 get_partially_filled_indices(const unsigned int row,
2181 const std::integral_constant<int, 2> &)
2182 {
2184 }
2185
2186
2187 template <int rank_>
2188 constexpr TableIndices<rank_>
2189 get_partially_filled_indices(const unsigned int row,
2190 const std::integral_constant<int, 4> &)
2191 {
2192 return TableIndices<rank_>(row,
2196 }
2197 } // namespace SymmetricTensorImplementation
2198} // namespace internal
2199
2200
2201template <int rank_, int dim, typename Number>
2202constexpr DEAL_II_ALWAYS_INLINE internal::SymmetricTensorAccessors::
2203 Accessor<rank_, dim, true, rank_ - 1, Number>
2204 SymmetricTensor<rank_, dim, Number>::operator[](const unsigned int row) const
2205{
2206 return internal::SymmetricTensorAccessors::
2207 Accessor<rank_, dim, true, rank_ - 1, Number>(
2208 *this,
2209 internal::SymmetricTensorImplementation::get_partially_filled_indices<
2210 rank_>(row, std::integral_constant<int, rank_>()));
2211}
2212
2213
2214
2215template <int rank_, int dim, typename Number>
2216constexpr inline DEAL_II_ALWAYS_INLINE internal::SymmetricTensorAccessors::
2217 Accessor<rank_, dim, false, rank_ - 1, Number>
2219{
2220 return internal::SymmetricTensorAccessors::
2221 Accessor<rank_, dim, false, rank_ - 1, Number>(
2222 *this,
2223 internal::SymmetricTensorImplementation::get_partially_filled_indices<
2224 rank_>(row, std::integral_constant<int, rank_>()));
2225}
2226
2227
2228
2229template <int rank_, int dim, typename Number>
2230constexpr DEAL_II_ALWAYS_INLINE const Number &
2232 const TableIndices<rank_> &indices) const
2233{
2234 return operator()(indices);
2235}
2236
2237
2238
2239template <int rank_, int dim, typename Number>
2240constexpr inline DEAL_II_ALWAYS_INLINE Number &
2242 const TableIndices<rank_> &indices)
2243{
2244 return operator()(indices);
2245}
2246
2247
2248
2249template <int rank_, int dim, typename Number>
2250inline Number *
2252{
2253 return std::addressof(this->access_raw_entry(0));
2254}
2255
2256
2257
2258template <int rank_, int dim, typename Number>
2259inline const Number *
2261{
2262 return std::addressof(this->access_raw_entry(0));
2263}
2264
2265
2266
2267template <int rank_, int dim, typename Number>
2268inline Number *
2270{
2271 return begin_raw() + n_independent_components;
2272}
2273
2274
2275
2276template <int rank_, int dim, typename Number>
2277inline const Number *
2279{
2280 return begin_raw() + n_independent_components;
2281}
2282
2283
2284
2285namespace internal
2286{
2287 namespace SymmetricTensorImplementation
2288 {
2289 template <int dim, typename Number>
2290 constexpr unsigned int
2291 entry_to_indices(const ::SymmetricTensor<2, dim, Number> &,
2292 const unsigned int index)
2293 {
2294 return index;
2295 }
2296
2297
2298 template <int dim, typename Number>
2299 constexpr ::TableIndices<2>
2300 entry_to_indices(const ::SymmetricTensor<4, dim, Number> &,
2301 const unsigned int index)
2302 {
2305 }
2306
2307 } // namespace SymmetricTensorImplementation
2308} // namespace internal
2309
2310
2311
2312template <int rank_, int dim, typename Number>
2313constexpr inline const Number &
2315 const unsigned int index) const
2316{
2317 AssertIndexRange(index, n_independent_components);
2318 return data[internal::SymmetricTensorImplementation::entry_to_indices(*this,
2319 index)];
2320}
2321
2322
2323
2324template <int rank_, int dim, typename Number>
2325constexpr inline Number &
2327{
2328 AssertIndexRange(index, n_independent_components);
2329 return data[internal::SymmetricTensorImplementation::entry_to_indices(*this,
2330 index)];
2331}
2332
2333
2334
2335namespace internal
2336{
2337 template <int dim, typename Number>
2338 constexpr inline typename numbers::NumberTraits<Number>::real_type
2339 compute_norm(const typename SymmetricTensorAccessors::
2340 StorageType<2, dim, Number>::base_tensor_type &data)
2341 {
2342 switch (dim)
2343 {
2344 case 1:
2345 return numbers::NumberTraits<Number>::abs(data[0]);
2346
2347 case 2:
2348 return std::sqrt(
2352
2353 case 3:
2354 return std::sqrt(
2361
2362 default:
2363 {
2364 typename numbers::NumberTraits<Number>::real_type return_value =
2366
2367 for (unsigned int d = 0; d < dim; ++d)
2368 return_value +=
2370 for (unsigned int d = dim; d < (dim * dim + dim) / 2; ++d)
2371 return_value +=
2373
2374 return std::sqrt(return_value);
2375 }
2376 }
2377 }
2378
2379
2380
2381 template <int dim, typename Number>
2382 constexpr inline typename numbers::NumberTraits<Number>::real_type
2383 compute_norm(const typename SymmetricTensorAccessors::
2384 StorageType<4, dim, Number>::base_tensor_type &data)
2385 {
2386 switch (dim)
2387 {
2388 case 1:
2389 return numbers::NumberTraits<Number>::abs(data[0][0]);
2390
2391 default:
2392 {
2393 typename numbers::NumberTraits<Number>::real_type return_value =
2395
2396 const unsigned int n_independent_components = data.dimension;
2397
2398 for (unsigned int i = 0; i < dim; ++i)
2399 for (unsigned int j = 0; j < dim; ++j)
2400 return_value +=
2402 for (unsigned int i = 0; i < dim; ++i)
2403 for (unsigned int j = dim; j < n_independent_components; ++j)
2404 return_value +=
2406 for (unsigned int i = dim; i < n_independent_components; ++i)
2407 for (unsigned int j = 0; j < dim; ++j)
2408 return_value +=
2410 for (unsigned int i = dim; i < n_independent_components; ++i)
2411 for (unsigned int j = dim; j < n_independent_components; ++j)
2412 return_value +=
2414
2415 return std::sqrt(return_value);
2416 }
2417 }
2418 }
2419
2420} // end of namespace internal
2421
2422
2423
2424template <int rank_, int dim, typename Number>
2427{
2428 return internal::compute_norm<dim, Number>(data);
2429}
2430
2431
2432
2433namespace internal
2434{
2435 namespace SymmetricTensorImplementation
2436 {
2437 // a function to do the unrolling from a set of indices to a
2438 // scalar index into the array in which we store the elements of
2439 // a symmetric tensor
2440 //
2441 // this function is for rank-2 tensors
2442 template <int dim>
2443 constexpr inline DEAL_II_ALWAYS_INLINE unsigned int
2445 {
2446 AssertIndexRange(indices[0], dim);
2447 AssertIndexRange(indices[1], dim);
2448
2449 switch (dim)
2450 {
2451 case 1:
2452 {
2453 return 0;
2454 }
2455
2456 case 2:
2457 {
2458 constexpr unsigned int table[2][2] = {{0, 2}, {2, 1}};
2459 return table[indices[0]][indices[1]];
2460 }
2461
2462 case 3:
2463 {
2464 constexpr unsigned int table[3][3] = {{0, 3, 4},
2465 {3, 1, 5},
2466 {4, 5, 2}};
2467 return table[indices[0]][indices[1]];
2468 }
2469
2470 case 4:
2471 {
2472 constexpr unsigned int table[4][4] = {{0, 4, 5, 6},
2473 {4, 1, 7, 8},
2474 {5, 7, 2, 9},
2475 {6, 8, 9, 3}};
2476 return table[indices[0]][indices[1]];
2477 }
2478
2479 default:
2480 // for the remainder, manually figure out the numbering
2481 {
2482 if (indices[0] == indices[1])
2483 return indices[0];
2484
2485 TableIndices<2> sorted_indices(indices);
2486 sorted_indices.sort();
2487
2488 for (unsigned int d = 0, c = 0; d < dim; ++d)
2489 for (unsigned int e = d + 1; e < dim; ++e, ++c)
2490 if ((sorted_indices[0] == d) && (sorted_indices[1] == e))
2491 return dim + c;
2492
2493 // should never get here:
2494 Assert(false, ExcInternalError());
2495 return 0;
2496 }
2497 }
2498 }
2499
2500 // a function to do the unrolling from a set of indices to a
2501 // scalar index into the array in which we store the elements of
2502 // a symmetric tensor
2503 //
2504 // this function is for tensors of ranks not already handled
2505 // above
2506 template <int dim, int rank_>
2507 constexpr inline unsigned int
2509 {
2510 (void)indices;
2511 Assert(false, ExcNotImplemented());
2513 }
2514 } // namespace SymmetricTensorImplementation
2515} // namespace internal
2516
2517
2518template <int rank_, int dim, typename Number>
2519constexpr unsigned int
2521 const TableIndices<rank_> &indices)
2522{
2523 return internal::SymmetricTensorImplementation::component_to_unrolled_index<
2524 dim>(indices);
2525}
2526
2527
2528
2529namespace internal
2530{
2531 namespace SymmetricTensorImplementation
2532 {
2533 // a function to do the inverse of the unrolling from a set of
2534 // indices to a scalar index into the array in which we store
2535 // the elements of a symmetric tensor. in other words, it goes
2536 // from the scalar index into the array to a set of indices of
2537 // the tensor
2538 //
2539 // this function is for rank-2 tensors
2540 template <int dim>
2541 constexpr inline DEAL_II_ALWAYS_INLINE TableIndices<2>
2542 unrolled_to_component_indices(const unsigned int i,
2543 const std::integral_constant<int, 2> &)
2544 {
2545 Assert(
2548 i,
2549 0,
2551 switch (dim)
2552 {
2553 case 1:
2554 {
2555 return {0, 0};
2556 }
2557
2558 case 2:
2559 {
2560 const TableIndices<2> table[3] = {TableIndices<2>(0, 0),
2561 TableIndices<2>(1, 1),
2562 TableIndices<2>(0, 1)};
2563 return table[i];
2564 }
2565
2566 case 3:
2567 {
2568 const TableIndices<2> table[6] = {TableIndices<2>(0, 0),
2569 TableIndices<2>(1, 1),
2570 TableIndices<2>(2, 2),
2571 TableIndices<2>(0, 1),
2572 TableIndices<2>(0, 2),
2573 TableIndices<2>(1, 2)};
2574 return table[i];
2575 }
2576
2577 default:
2578 if (i < dim)
2579 return {i, i};
2580
2581 for (unsigned int d = 0, c = dim; d < dim; ++d)
2582 for (unsigned int e = d + 1; e < dim; ++e, ++c)
2583 if (c == i)
2584 return {d, e};
2585
2586 // should never get here:
2587 Assert(false, ExcInternalError());
2588 return {0, 0};
2589 }
2590 }
2591
2592 // a function to do the inverse of the unrolling from a set of
2593 // indices to a scalar index into the array in which we store
2594 // the elements of a symmetric tensor. in other words, it goes
2595 // from the scalar index into the array to a set of indices of
2596 // the tensor
2597 //
2598 // this function is for tensors of a rank not already handled
2599 // above
2600 template <int dim, int rank_>
2601 constexpr inline
2602 typename std::enable_if<rank_ != 2, TableIndices<rank_>>::type
2603 unrolled_to_component_indices(const unsigned int i,
2604 const std::integral_constant<int, rank_> &)
2605 {
2606 (void)i;
2607 Assert(
2608 (i <
2610 ExcIndexRange(i,
2611 0,
2613 n_independent_components));
2614 Assert(false, ExcNotImplemented());
2615 return TableIndices<rank_>();
2616 }
2617
2618 } // namespace SymmetricTensorImplementation
2619} // namespace internal
2620
2621template <int rank_, int dim, typename Number>
2624 const unsigned int i)
2625{
2626 return internal::SymmetricTensorImplementation::unrolled_to_component_indices<
2627 dim>(i, std::integral_constant<int, rank_>());
2628}
2629
2630
2631
2632template <int rank_, int dim, typename Number>
2633template <class Archive>
2634inline void
2635SymmetricTensor<rank_, dim, Number>::serialize(Archive &ar, const unsigned int)
2636{
2637 ar &data;
2638}
2639
2640
2641#endif // DOXYGEN
2642
2643/* ----------------- Non-member functions operating on tensors. ------------ */
2644
2645
2658template <int rank_, int dim, typename Number, typename OtherNumber>
2659constexpr inline DEAL_II_ALWAYS_INLINE
2663{
2665 tmp = left;
2666 tmp += right;
2667 return tmp;
2668}
2669
2670
2683template <int rank_, int dim, typename Number, typename OtherNumber>
2684constexpr inline DEAL_II_ALWAYS_INLINE
2688{
2690 tmp = left;
2691 tmp -= right;
2692 return tmp;
2693}
2694
2695
2703template <int rank_, int dim, typename Number, typename OtherNumber>
2704constexpr DEAL_II_ALWAYS_INLINE
2707 const Tensor<rank_, dim, OtherNumber> & right)
2708{
2709 return Tensor<rank_, dim, Number>(left) + right;
2710}
2711
2712
2720template <int rank_, int dim, typename Number, typename OtherNumber>
2721constexpr DEAL_II_ALWAYS_INLINE
2725{
2726 return left + Tensor<rank_, dim, OtherNumber>(right);
2727}
2728
2729
2737template <int rank_, int dim, typename Number, typename OtherNumber>
2738constexpr DEAL_II_ALWAYS_INLINE
2741 const Tensor<rank_, dim, OtherNumber> & right)
2742{
2743 return Tensor<rank_, dim, Number>(left) - right;
2744}
2745
2746
2754template <int rank_, int dim, typename Number, typename OtherNumber>
2755constexpr DEAL_II_ALWAYS_INLINE
2759{
2760 return left - Tensor<rank_, dim, OtherNumber>(right);
2761}
2762
2763
2764
2765template <int dim, typename Number>
2768{
2769 switch (dim)
2770 {
2771 case 1:
2772 return t.data[0];
2773 case 2:
2774 return (t.data[0] * t.data[1] - t.data[2] * t.data[2]);
2775 case 3:
2776 {
2777 // in analogy to general tensors, but
2778 // there's something to be simplified for
2779 // the present case
2780 const Number tmp = t.data[3] * t.data[4] * t.data[5];
2781 return (tmp + tmp + t.data[0] * t.data[1] * t.data[2] -
2782 t.data[0] * t.data[5] * t.data[5] -
2783 t.data[1] * t.data[4] * t.data[4] -
2784 t.data[2] * t.data[3] * t.data[3]);
2785 }
2786 default:
2787 Assert(false, ExcNotImplemented());
2789 }
2790}
2791
2792
2793
2805template <int dim, typename Number>
2808{
2809 return determinant(t);
2810}
2811
2812
2813
2814template <int dim, typename Number>
2815constexpr inline DEAL_II_ALWAYS_INLINE Number
2817{
2818 Number t = d.data[0];
2819 for (unsigned int i = 1; i < dim; ++i)
2820 t += d.data[i];
2821 return t;
2822}
2823
2824
2836template <int dim, typename Number>
2837constexpr Number
2839{
2840 return trace(t);
2841}
2842
2843
2855template <typename Number>
2856constexpr DEAL_II_ALWAYS_INLINE Number
2858{
2860}
2861
2862
2863
2882template <typename Number>
2883constexpr DEAL_II_ALWAYS_INLINE Number
2885{
2886 return t[0][0] * t[1][1] - t[0][1] * t[0][1];
2887}
2888
2889
2890
2899template <typename Number>
2900constexpr DEAL_II_ALWAYS_INLINE Number
2902{
2903 return (t[0][0] * t[1][1] + t[1][1] * t[2][2] + t[2][2] * t[0][0] -
2904 t[0][1] * t[0][1] - t[0][2] * t[0][2] - t[1][2] * t[1][2]);
2905}
2906
2907
2908
2916template <typename Number>
2917std::array<Number, 1>
2919
2920
2921
2944template <typename Number>
2945std::array<Number, 2>
2947
2948
2949
2972template <typename Number>
2973std::array<Number, 3>
2975
2976
2977
2978namespace internal
2979{
2980 namespace SymmetricTensorImplementation
2981 {
3019 template <int dim, typename Number>
3020 void
3021 tridiagonalize(const ::SymmetricTensor<2, dim, Number> &A,
3023 std::array<Number, dim> & d,
3024 std::array<Number, dim - 1> & e);
3025
3026
3027
3067 template <int dim, typename Number>
3068 std::array<std::pair<Number, Tensor<1, dim, Number>>, dim>
3069 ql_implicit_shifts(const ::SymmetricTensor<2, dim, Number> &A);
3070
3071
3072
3112 template <int dim, typename Number>
3113 std::array<std::pair<Number, Tensor<1, dim, Number>>, dim>
3115
3116
3117
3131 template <typename Number>
3132 std::array<std::pair<Number, Tensor<1, 2, Number>>, 2>
3133 hybrid(const ::SymmetricTensor<2, 2, Number> &A);
3134
3135
3136
3169 template <typename Number>
3170 std::array<std::pair<Number, Tensor<1, 3, Number>>, 3>
3171 hybrid(const ::SymmetricTensor<2, 3, Number> &A);
3172
3177 template <int dim, typename Number>
3179 {
3180 using EigValsVecs = std::pair<Number, Tensor<1, dim, Number>>;
3181 bool
3182 operator()(const EigValsVecs &lhs, const EigValsVecs &rhs)
3183 {
3184 return lhs.first > rhs.first;
3185 }
3186 };
3187
3188 } // namespace SymmetricTensorImplementation
3189
3190} // namespace internal
3191
3192
3193
3194// The line below is to ensure that doxygen puts the full description
3195// of this global enumeration into the documentation
3196// See https://stackoverflow.com/a/1717984
3226{
3236 hybrid,
3254 jacobi
3255};
3256
3257
3258
3287template <int dim, typename Number>
3288std::array<std::pair<Number, Tensor<1, dim, Number>>,
3289 std::integral_constant<int, dim>::value>
3293
3294
3295
3304template <int rank_, int dim, typename Number>
3307{
3308 return t;
3309}
3310
3311
3312
3313template <int dim, typename Number>
3316{
3318
3319 // subtract scaled trace from the diagonal
3320 const Number tr = trace(t) / dim;
3321 for (unsigned int i = 0; i < dim; ++i)
3322 tmp.data[i] -= tr;
3323
3324 return tmp;
3325}
3326
3327
3328
3329template <int dim, typename Number>
3332{
3333 // create a default constructed matrix filled with
3334 // zeros, then set the diagonal elements to one
3336 switch (dim)
3337 {
3338 case 1:
3340 break;
3341 case 2:
3342 tmp.data[0] = tmp.data[1] = internal::NumberType<Number>::value(1.);
3343 break;
3344 case 3:
3345 tmp.data[0] = tmp.data[1] = tmp.data[2] =
3347 break;
3348 default:
3349 for (unsigned int d = 0; d < dim; ++d)
3351 }
3352 return tmp;
3353}
3354
3355
3356
3357template <int dim, typename Number>
3360{
3362
3363 // fill the elements treating the diagonal
3364 for (unsigned int i = 0; i < dim; ++i)
3365 for (unsigned int j = 0; j < dim; ++j)
3366 tmp.data[i][j] =
3367 internal::NumberType<Number>::value((i == j ? 1. : 0.) - 1. / dim);
3368
3369 // then fill the ones that copy over the
3370 // non-diagonal elements. note that during
3371 // the double-contraction, we handle the
3372 // off-diagonal elements twice, so simply
3373 // copying requires a weight of 1/2
3374 for (unsigned int i = dim;
3375 i < internal::SymmetricTensorAccessors::StorageType<4, dim, Number>::
3376 n_rank2_components;
3377 ++i)
3379
3380 return tmp;
3381}
3382
3383
3384
3385template <int dim, typename Number>
3388{
3390
3391 // fill the elements treating the diagonal
3392 for (unsigned int i = 0; i < dim; ++i)
3394
3395 // then fill the ones that copy over the
3396 // non-diagonal elements. note that during
3397 // the double-contraction, we handle the
3398 // off-diagonal elements twice, so simply
3399 // copying requires a weight of 1/2
3400 for (unsigned int i = dim;
3401 i < internal::SymmetricTensorAccessors::StorageType<4, dim, Number>::
3402 n_rank2_components;
3403 ++i)
3405
3406 return tmp;
3407}
3408
3409
3410
3420template <int dim, typename Number>
3423{
3425 value(t);
3426}
3427
3428
3429
3440template <int dim, typename Number>
3443{
3445 value(t);
3446}
3447
3448
3449
3471template <int dim, typename Number>
3472constexpr inline SymmetricTensor<4, dim, Number>
3475{
3477
3478 // fill only the elements really needed
3479 for (unsigned int i = 0; i < dim; ++i)
3480 for (unsigned int j = i; j < dim; ++j)
3481 for (unsigned int k = 0; k < dim; ++k)
3482 for (unsigned int l = k; l < dim; ++l)
3483 tmp[i][j][k][l] = t1[i][j] * t2[k][l];
3484
3485 return tmp;
3486}
3487
3488
3489
3497template <int dim, typename Number>
3500{
3502 for (unsigned int d = 0; d < dim; ++d)
3503 result[d][d] = t[d][d];
3504
3505 const Number half = internal::NumberType<Number>::value(0.5);
3506 for (unsigned int d = 0; d < dim; ++d)
3507 for (unsigned int e = d + 1; e < dim; ++e)
3508 result[d][e] = (t[d][e] + t[e][d]) * half;
3509 return result;
3510}
3511
3512
3513
3521template <int rank_, int dim, typename Number>
3523operator*(const SymmetricTensor<rank_, dim, Number> &t, const Number &factor)
3524{
3526 tt *= factor;
3527 return tt;
3528}
3529
3530
3531
3539template <int rank_, int dim, typename Number>
3541operator*(const Number &factor, const SymmetricTensor<rank_, dim, Number> &t)
3542{
3543 // simply forward to the other operator
3544 return t * factor;
3545}
3546
3547
3548
3574template <int rank_, int dim, typename Number, typename OtherNumber>
3575constexpr inline DEAL_II_ALWAYS_INLINE SymmetricTensor<
3576 rank_,
3577 dim,
3578 typename ProductType<Number,
3579 typename EnableIfScalar<OtherNumber>::type>::type>
3581 const OtherNumber & factor)
3582{
3583 // form the product. we have to convert the two factors into the final
3584 // type via explicit casts because, for awkward reasons, the C++
3585 // standard committee saw it fit to not define an
3586 // operator*(float,std::complex<double>)
3587 // (as well as with switched arguments and double<->float).
3588 using product_type = typename ProductType<Number, OtherNumber>::type;
3591 return tt;
3592}
3593
3594
3595
3604template <int rank_, int dim, typename Number, typename OtherNumber>
3605constexpr inline DEAL_II_ALWAYS_INLINE SymmetricTensor<
3606 rank_,
3607 dim,
3608 typename ProductType<OtherNumber,
3609 typename EnableIfScalar<Number>::type>::type>
3610operator*(const Number & factor,
3612{
3613 // simply forward to the other operator with switched arguments
3614 return (t * factor);
3615}
3616
3617
3618
3624template <int rank_, int dim, typename Number, typename OtherNumber>
3625constexpr inline SymmetricTensor<
3626 rank_,
3627 dim,
3628 typename ProductType<Number,
3629 typename EnableIfScalar<OtherNumber>::type>::type>
3631 const OtherNumber & factor)
3632{
3633 using product_type = typename ProductType<Number, OtherNumber>::type;
3636 return tt;
3637}
3638
3639
3640
3647template <int rank_, int dim>
3649operator*(const SymmetricTensor<rank_, dim> &t, const double factor)
3650{
3652 tt *= factor;
3653 return tt;
3654}
3655
3656
3657
3664template <int rank_, int dim>
3666operator*(const double factor, const SymmetricTensor<rank_, dim> &t)
3667{
3669 tt *= factor;
3670 return tt;
3671}
3672
3673
3674
3680template <int rank_, int dim>
3681constexpr inline SymmetricTensor<rank_, dim>
3682operator/(const SymmetricTensor<rank_, dim> &t, const double factor)
3683{
3685 tt /= factor;
3686 return tt;
3687}
3688
3698template <int dim, typename Number, typename OtherNumber>
3702{
3703 return (t1 * t2);
3704}
3705
3706
3720template <int dim, typename Number, typename OtherNumber>
3721constexpr inline DEAL_II_ALWAYS_INLINE
3724 const Tensor<2, dim, OtherNumber> & t2)
3725{
3727 typename ProductType<Number, OtherNumber>::type>::value(0.0);
3728 for (unsigned int i = 0; i < dim; ++i)
3729 for (unsigned int j = 0; j < dim; ++j)
3730 s += t1[i][j] * t2[i][j];
3731 return s;
3732}
3733
3734
3748template <int dim, typename Number, typename OtherNumber>
3752{
3753 return scalar_product(t2, t1);
3754}
3755
3756
3771template <typename Number, typename OtherNumber>
3772constexpr inline DEAL_II_ALWAYS_INLINE void
3777{
3778 tmp[0][0] = t[0][0][0][0] * s[0][0];
3779}
3780
3781
3782
3797template <typename Number, typename OtherNumber>
3798constexpr inline void
3803{
3804 tmp[0][0] = t[0][0][0][0] * s[0][0];
3805}
3806
3807
3808
3823template <typename Number, typename OtherNumber>
3824constexpr inline void
3829{
3830 const unsigned int dim = 2;
3831
3832 for (unsigned int i = 0; i < dim; ++i)
3833 for (unsigned int j = i; j < dim; ++j)
3834 tmp[i][j] = t[i][j][0][0] * s[0][0] + t[i][j][1][1] * s[1][1] +
3835 2 * t[i][j][0][1] * s[0][1];
3836}
3837
3838
3839
3854template <typename Number, typename OtherNumber>
3855constexpr inline void
3860{
3861 const unsigned int dim = 2;
3862
3863 for (unsigned int i = 0; i < dim; ++i)
3864 for (unsigned int j = i; j < dim; ++j)
3865 tmp[i][j] = s[0][0] * t[0][0][i][j] * +s[1][1] * t[1][1][i][j] +
3866 2 * s[0][1] * t[0][1][i][j];
3867}
3868
3869
3870
3885template <typename Number, typename OtherNumber>
3886constexpr inline void
3891{
3892 const unsigned int dim = 3;
3893
3894 for (unsigned int i = 0; i < dim; ++i)
3895 for (unsigned int j = i; j < dim; ++j)
3896 tmp[i][j] = t[i][j][0][0] * s[0][0] + t[i][j][1][1] * s[1][1] +
3897 t[i][j][2][2] * s[2][2] + 2 * t[i][j][0][1] * s[0][1] +
3898 2 * t[i][j][0][2] * s[0][2] + 2 * t[i][j][1][2] * s[1][2];
3899}
3900
3901
3902
3917template <typename Number, typename OtherNumber>
3918constexpr inline void
3923{
3924 const unsigned int dim = 3;
3925
3926 for (unsigned int i = 0; i < dim; ++i)
3927 for (unsigned int j = i; j < dim; ++j)
3928 tmp[i][j] = s[0][0] * t[0][0][i][j] + s[1][1] * t[1][1][i][j] +
3929 s[2][2] * t[2][2][i][j] + 2 * s[0][1] * t[0][1][i][j] +
3930 2 * s[0][2] * t[0][2][i][j] + 2 * s[1][2] * t[1][2][i][j];
3931}
3932
3933
3934
3941template <int dim, typename Number, typename OtherNumber>
3944 const Tensor<1, dim, OtherNumber> & src2)
3945{
3947 for (unsigned int i = 0; i < dim; ++i)
3948 for (unsigned int j = 0; j < dim; ++j)
3949 dest[i] += src1[i][j] * src2[j];
3950 return dest;
3951}
3952
3953
3960template <int dim, typename Number, typename OtherNumber>
3964{
3965 // this is easy for symmetric tensors:
3966 return src2 * src1;
3967}
3968
3969
3970
3990template <int rank_1,
3991 int rank_2,
3992 int dim,
3993 typename Number,
3994 typename OtherNumber>
3995constexpr DEAL_II_ALWAYS_INLINE
3996 typename Tensor<rank_1 + rank_2 - 2,
3997 dim,
3998 typename ProductType<Number, OtherNumber>::type>::tensor_type
4001{
4002 return src1 * Tensor<rank_2, dim, OtherNumber>(src2);
4003}
4004
4005
4006
4026template <int rank_1,
4027 int rank_2,
4028 int dim,
4029 typename Number,
4030 typename OtherNumber>
4031constexpr DEAL_II_ALWAYS_INLINE
4032 typename Tensor<rank_1 + rank_2 - 2,
4033 dim,
4034 typename ProductType<Number, OtherNumber>::type>::tensor_type
4037{
4038 return Tensor<rank_1, dim, Number>(src1) * src2;
4039}
4040
4041
4042
4052template <int dim, typename Number>
4053inline std::ostream &
4054operator<<(std::ostream &out, const SymmetricTensor<2, dim, Number> &t)
4055{
4056 // make our lives a bit simpler by outputting
4057 // the tensor through the operator for the
4058 // general Tensor class
4060
4061 for (unsigned int i = 0; i < dim; ++i)
4062 for (unsigned int j = 0; j < dim; ++j)
4063 tt[i][j] = t[i][j];
4064
4065 return out << tt;
4066}
4067
4068
4069
4079template <int dim, typename Number>
4080inline std::ostream &
4081operator<<(std::ostream &out, const SymmetricTensor<4, dim, Number> &t)
4082{
4083 // make our lives a bit simpler by outputting
4084 // the tensor through the operator for the
4085 // general Tensor class
4087
4088 for (unsigned int i = 0; i < dim; ++i)
4089 for (unsigned int j = 0; j < dim; ++j)
4090 for (unsigned int k = 0; k < dim; ++k)
4091 for (unsigned int l = 0; l < dim; ++l)
4092 tt[i][j][k][l] = t[i][j][k][l];
4093
4094 return out << tt;
4095}
4096
4097
4099
4100#endif
constexpr SymmetricTensor< 2, dim, Number > deviator(const SymmetricTensor< 2, dim, Number > &)
constexpr bool operator==(const SymmetricTensor &) const
constexpr Number first_invariant(const SymmetricTensor< 2, dim, Number > &t)
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)
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)
constexpr ProductType< Number, OtherNumber >::type scalar_product(const Tensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, OtherNumber > &t2)
constexpr SymmetricTensor< 4, dim, Number > invert(const SymmetricTensor< 4, dim, Number > &t)
constexpr SymmetricTensor< rank_, dim > operator*(const SymmetricTensor< rank_, dim > &t, const double factor)
constexpr Tensor< 1, dim, typename ProductType< Number, OtherNumber >::type > operator*(const SymmetricTensor< 2, dim, Number > &src1, const Tensor< 1, dim, OtherNumber > &src2)
constexpr SymmetricTensor< 2, dim, Number > symmetrize(const Tensor< 2, dim, Number > &t)
constexpr SymmetricTensor(const Number(&array)[n_independent_components])
constexpr Tensor< rank_, dim, typename ProductType< Number, OtherNumber >::type > operator-(const SymmetricTensor< rank_, dim, Number > &left, const Tensor< rank_, dim, OtherNumber > &right)
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 constexpr unsigned int component_to_unrolled_index(const TableIndices< rank_ > &indices)
constexpr Number determinant(const SymmetricTensor< 2, dim, Number > &)
constexpr SymmetricTensor< 2, dim, Number > invert(const SymmetricTensor< 2, dim, Number > &t)
constexpr Tensor< 1, dim, typename ProductType< Number, OtherNumber >::type > operator*(const Tensor< 1, dim, Number > &src1, const SymmetricTensor< 2, dim, OtherNumber > &src2)
std::array< Number, 2 > eigenvalues(const SymmetricTensor< 2, 2, Number > &T)
void serialize(Archive &ar, const unsigned int version)
constexpr Tensor< rank_, dim, typename ProductType< Number, OtherNumber >::type > operator-(const Tensor< rank_, dim, Number > &left, const SymmetricTensor< rank_, dim, OtherNumber > &right)
const Number * begin_raw() const
const Number * end_raw() const
constexpr Number trace(const SymmetricTensor< 2, dim2, Number > &)
std::array< Number, 1 > eigenvalues(const SymmetricTensor< 2, 1, Number > &T)
constexpr internal::SymmetricTensorAccessors::Accessor< rank_, dim, false, rank_ - 1, Number > operator[](const unsigned int row)
typename base_tensor_descriptor::base_tensor_type base_tensor_type
constexpr const Number & operator()(const TableIndices< rank_ > &indices) const
constexpr SymmetricTensor< 4, dim, Number > deviator_tensor()
constexpr bool operator!=(const SymmetricTensor &) const
constexpr Number & operator[](const TableIndices< rank_ > &indices)
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)
constexpr SymmetricTensor< rank_, dim, typename ProductType< Number, typename EnableIfScalar< OtherNumber >::type >::type > operator/(const SymmetricTensor< rank_, dim, Number > &t, const OtherNumber &factor)
static constexpr std::size_t memory_consumption()
constexpr ProductType< Number, OtherNumber >::type scalar_product(const SymmetricTensor< 2, dim, Number > &t1, const Tensor< 2, dim, OtherNumber > &t2)
constexpr Tensor< rank_, dim, typename ProductType< Number, OtherNumber >::type > operator+(const SymmetricTensor< rank_, dim, Number > &left, const Tensor< rank_, dim, OtherNumber > &right)
Number * begin_raw()
base_tensor_type data
constexpr const Number & operator[](const TableIndices< rank_ > &indices) const
constexpr SymmetricTensor & operator=(const Number &d)
SymmetricTensor(const Tensor< 2, dim, OtherNumber > &t)
static constexpr TableIndices< rank_ > unrolled_to_component_indices(const unsigned int i)
constexpr SymmetricTensor< 4, dim, Number > outer_product(const SymmetricTensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, Number > &t2)
constexpr Number & access_raw_entry(const unsigned int unrolled_index)
constexpr numbers::NumberTraits< Number >::real_type norm() const
constexpr SymmetricTensor operator-() const
constexpr internal::SymmetricTensorAccessors::double_contraction_result< rank_, 2, dim, Number, OtherNumber >::type operator*(const SymmetricTensor< 2, dim, OtherNumber > &s) const
constexpr SymmetricTensor()=default
std::array< std::pair< Number, Tensor< 1, dim, Number > >, std::integral_constant< int, dim >::value > eigenvectors(const SymmetricTensor< 2, dim, Number > &T, const SymmetricTensorEigenvectorMethod method=SymmetricTensorEigenvectorMethod::ql_implicit_shifts)
constexpr Number second_invariant(const SymmetricTensor< 2, 1, Number > &)
constexpr Number third_invariant(const SymmetricTensor< 2, dim, Number > &t)
constexpr SymmetricTensor(const SymmetricTensor< rank_, dim, OtherNumber > &initializer)
constexpr SymmetricTensor & operator-=(const SymmetricTensor< rank_, dim, OtherNumber > &)
constexpr SymmetricTensor< rank_, dim, Number > operator*(const Number &factor, const SymmetricTensor< rank_, dim, Number > &t)
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)
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)
constexpr ProductType< Number, OtherNumber >::type scalar_product(const SymmetricTensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, OtherNumber > &t2)
constexpr SymmetricTensor< 4, dim, Number > identity_tensor()
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)
constexpr SymmetricTensor< rank_, dim, typename ProductType< Number, OtherNumber >::type > operator-(const SymmetricTensor< rank_, dim, Number > &left, const SymmetricTensor< rank_, dim, OtherNumber > &right)
constexpr SymmetricTensor< rank_, dim, typename ProductType< Number, OtherNumber >::type > operator+(const SymmetricTensor< rank_, dim, Number > &left, const SymmetricTensor< rank_, dim, OtherNumber > &right)
constexpr Number second_invariant(const SymmetricTensor< 2, 3, Number > &t)
constexpr SymmetricTensor< rank_, dim, Number > operator*(const SymmetricTensor< rank_, dim, Number > &t, const Number &factor)
constexpr const Number & access_raw_entry(const unsigned int unrolled_index) const
constexpr SymmetricTensor & operator=(const SymmetricTensor< rank_, dim, OtherNumber > &rhs)
constexpr SymmetricTensor< rank_, dim, Number > transpose(const SymmetricTensor< rank_, dim, Number > &t)
constexpr SymmetricTensor< rank_, dim > operator*(const double factor, const SymmetricTensor< rank_, dim > &t)
constexpr SymmetricTensor & operator/=(const OtherNumber &factor)
constexpr void clear()
constexpr Tensor< rank_, dim, typename ProductType< Number, OtherNumber >::type > operator+(const Tensor< rank_, dim, Number > &left, const SymmetricTensor< rank_, dim, OtherNumber > &right)
constexpr Number second_invariant(const SymmetricTensor< 2, 2, Number > &t)
constexpr SymmetricTensor & operator+=(const SymmetricTensor< rank_, dim, OtherNumber > &)
constexpr SymmetricTensor< 2, dim, Number > unit_symmetric_tensor()
constexpr internal::SymmetricTensorAccessors::double_contraction_result< rank_, 4, dim, Number, OtherNumber >::type operator*(const SymmetricTensor< 4, dim, OtherNumber > &s) const
constexpr SymmetricTensor< rank_, dim > operator/(const SymmetricTensor< rank_, dim > &t, const double factor)
std::array< Number, 3 > eigenvalues(const SymmetricTensor< 2, 3, Number > &T)
Number * end_raw()
constexpr internal::SymmetricTensorAccessors::Accessor< rank_, dim, true, rank_ - 1, Number > operator[](const unsigned int row) const
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)
constexpr SymmetricTensor & operator*=(const OtherNumber &factor)
constexpr Number & operator()(const TableIndices< rank_ > &indices)
Definition: tensor.h:503
typename AccessorTypes< rank, dim, constness, Number >::reference reference
constexpr Accessor(tensor_type &tensor, const TableIndices< rank > &previous_indices)
typename AccessorTypes< rank, dim, constness, Number >::tensor_type tensor_type
typename AccessorTypes< rank, dim, constness, Number >::tensor_type tensor_type
constexpr Accessor< rank, dim, constness, P - 1, Number > operator[](const unsigned int i)
constexpr Accessor(tensor_type &tensor, const TableIndices< rank > &previous_indices)
constexpr Accessor(const Accessor &)=default
typename AccessorTypes< rank, dim, constness, Number >::reference reference
constexpr Accessor< rank, dim, constness, P - 1, Number > operator[](const unsigned int i) const
#define DEAL_II_ALWAYS_INLINE
Definition: config.h:102
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:442
#define DEAL_II_CONSTEXPR
Definition: config.h:177
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:443
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
Definition: exceptions.h:1473
#define AssertIndexRange(index, range)
Definition: exceptions.h:1732
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcIndexRange(std::size_t arg1, std::size_t arg2, std::size_t arg3)
static ::ExceptionBase & ExcMessage(std::string arg1)
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)
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:943
static const unsigned int invalid_unsigned_int
Definition: types.h:201
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 > &)
constexpr SymmetricTensor< rank_, dim, typename ProductType< OtherNumber, typename EnableIfScalar< Number >::type >::type > operator*(const Number &factor, const SymmetricTensor< rank_, dim, OtherNumber > &t)
constexpr SymmetricTensor< rank_, dim, typename ProductType< Number, typename EnableIfScalar< OtherNumber >::type >::type > operator*(const SymmetricTensor< rank_, dim, Number > &t, const OtherNumber &factor)
typename internal::ProductTypeImpl< typename std::decay< T >::type, typename std::decay< U >::type >::type type
static constexpr const T & value(const T &t)
Definition: numbers.h:705
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:611
constexpr SymmetricTensor< 2, dim, Number > deviator(const SymmetricTensor< 2, dim, Number > &)
constexpr Number determinant(const SymmetricTensor< 2, dim, Number > &)
constexpr SymmetricTensor< 2, dim, Number > invert(const SymmetricTensor< 2, dim, Number > &)
constexpr Number trace(const SymmetricTensor< 2, dim2, Number > &)
constexpr SymmetricTensor< 4, dim, Number > deviator_tensor()
std::ostream & operator<<(std::ostream &out, const SymmetricTensor< 2, dim, Number > &t)
constexpr ProductType< Number, OtherNumber >::type scalar_product(const SymmetricTensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, OtherNumber > &t2)
constexpr SymmetricTensor< 4, dim, Number > identity_tensor()
SymmetricTensorEigenvectorMethod
constexpr SymmetricTensor< 2, dim, Number > unit_symmetric_tensor()