deal.II version GIT relicensing-6809-ge913b9bb34 2026-09-25 17:20:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
tensor.h
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 1998 - 2025 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13#ifndef dealii_tensor_h
14#define dealii_tensor_h
15
16#include <deal.II/base/config.h>
17
19#include <deal.II/base/kokkos.h>
24
25#include <Kokkos_Array.hpp>
26
27#ifdef DEAL_II_WITH_ADOLC
28# include <adolc/adouble.h> // Taped double
29#endif
30
31#include <cmath>
32#include <complex>
33#include <ostream>
34#include <type_traits>
35
37
38// Forward declarations:
39#ifndef DOXYGEN
40template <typename ElementType, typename MemorySpace>
41class ArrayView;
42
43template <int dim, typename Number>
45class Point;
46
47template <int rank_, int dim, typename Number = double>
48class Tensor;
49template <typename Number>
50class Vector;
51template <typename number>
52class FullMatrix;
53namespace Differentiation
54{
55 namespace SD
56 {
57 class Expression;
58 }
59} // namespace Differentiation
60#endif
61
62
92template <int dim, typename Number>
93class Tensor<0, dim, Number>
94{
95public:
96 static_assert(dim >= 0,
97 "Tensors must have a dimension greater than or equal to one.");
98
107 static constexpr unsigned int dimension = dim;
108
112 static constexpr unsigned int rank = 0;
113
117 static constexpr unsigned int n_independent_components = 1;
118
128
133 using value_type = Number;
134
140 using array_type = Number;
141
147 constexpr DEAL_II_HOST_DEVICE
149
157 template <typename OtherNumber>
158 constexpr DEAL_II_HOST_DEVICE
160
166 template <typename OtherNumber>
167 constexpr DEAL_II_HOST_DEVICE
168 Tensor(const OtherNumber &initializer);
169
170#ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
174 constexpr DEAL_II_HOST_DEVICE
175 Tensor(const Tensor<0, dim, Number> &other);
176
180 constexpr DEAL_II_HOST_DEVICE
181 Tensor(Tensor<0, dim, Number> &&other) noexcept;
182#endif
183
193 constexpr DEAL_II_HOST_DEVICE
194 operator Number &();
195
204 constexpr DEAL_II_HOST_DEVICE operator const Number &() const;
205
213 template <typename OtherNumber>
214 constexpr DEAL_II_HOST_DEVICE Tensor &
216
217#if defined(__INTEL_COMPILER) || defined(DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG)
226 constexpr DEAL_II_HOST_DEVICE Tensor &
228#endif
229
230#ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
235 operator=(Tensor<0, dim, Number> &&other) noexcept;
236#endif
237
244 template <typename OtherNumber>
245 constexpr DEAL_II_HOST_DEVICE Tensor &
246 operator=(const OtherNumber &d) &;
247
253 template <typename OtherNumber>
254 constexpr DEAL_II_HOST_DEVICE Tensor &
255 operator=(const OtherNumber &d) && = delete;
256
260 template <typename OtherNumber>
261 constexpr bool
263
267 template <typename OtherNumber>
268 constexpr bool
270
276 template <typename OtherNumber>
277 constexpr DEAL_II_HOST_DEVICE Tensor &
279
285 template <typename OtherNumber>
286 constexpr DEAL_II_HOST_DEVICE Tensor &
288
294 template <typename OtherNumber>
295 constexpr DEAL_II_HOST_DEVICE Tensor &
296 operator*=(const OtherNumber &factor);
297
303 template <typename OtherNumber>
304 constexpr DEAL_II_HOST_DEVICE Tensor &
305 operator/=(const OtherNumber &factor);
306
313 operator-() const;
314
327 constexpr void
329
336 norm() const;
337
345 norm_square() const;
346
354 template <class Iterator>
355 void
356 unroll(const Iterator begin, const Iterator end) const;
357
363 template <class Archive>
364 void
365 serialize(Archive &ar, const unsigned int version);
366
371 using tensor_type = Number;
372
373private:
377 Number value;
378
379 // Allow an arbitrary Tensor to access the underlying values.
380 template <int, int, typename>
381 friend class Tensor;
382};
383
384
385
459template <int rank_, int dim, typename Number>
461{
462public:
463 static_assert(rank_ >= 1,
464 "Tensors must have a rank greater than or equal to one.");
465 static_assert(dim >= 0,
466 "Tensors must have a dimension greater than or equal to zero.");
475 static constexpr unsigned int dimension = dim;
476
480 static constexpr unsigned int rank = rank_;
481
496 static constexpr unsigned int n_independent_components =
497 Tensor<rank_ - 1, dim>::n_independent_components * dim;
498
505 std::conditional_t<rank_ == 1, Number, Tensor<rank_ - 1, dim, Number>>;
506
518 using array_type = std::conditional_t<
519 rank_ == 1,
520 Number[(dim != 0) ? dim : 1],
521 typename Tensor<rank_ - 1, dim, Number>::array_type[(dim != 0) ? dim : 1]>;
522
530
536 constexpr DEAL_II_HOST_DEVICE explicit Tensor(const array_type &initializer);
537
550 template <typename ElementType, typename MemorySpace>
551 constexpr DEAL_II_HOST_DEVICE explicit Tensor(
552 const ArrayView<ElementType, MemorySpace> &initializer);
553
561 template <typename OtherNumber>
562 constexpr DEAL_II_HOST_DEVICE
564
568 template <typename OtherNumber>
569 constexpr Tensor(
570 const Tensor<1, dim, Tensor<rank_ - 1, dim, OtherNumber>> &initializer);
571
575 template <typename OtherNumber>
576 constexpr
577 operator Tensor<1, dim, Tensor<rank_ - 1, dim, OtherNumber>>() const;
578
579#ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
583 constexpr Tensor(const Tensor<rank_, dim, Number> &);
584
588 constexpr Tensor(Tensor<rank_, dim, Number> &&) noexcept;
589#endif
590
597 operator[](const unsigned int i);
598
604 constexpr DEAL_II_HOST_DEVICE const value_type &
605 operator[](const unsigned int i) const;
606
610 constexpr const Number &
611 operator[](const TableIndices<rank_> &indices) const;
612
616 constexpr Number &
618
623 Number *
625
630 const Number *
631 begin_raw() const;
632
637 Number *
639
644 const Number *
645 end_raw() const;
646
654 template <typename OtherNumber>
655 constexpr DEAL_II_HOST_DEVICE Tensor &
657
664 constexpr DEAL_II_HOST_DEVICE Tensor &
665 operator=(const Number &d) &;
666
672 constexpr DEAL_II_HOST_DEVICE Tensor &
673 operator=(const Number &d) && = delete;
674
675#ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
681
687#endif
688
692 template <typename OtherNumber>
693 constexpr bool
695
699 template <typename OtherNumber>
700 constexpr bool
702
708 template <typename OtherNumber>
709 constexpr DEAL_II_HOST_DEVICE Tensor &
711
717 template <typename OtherNumber>
718 constexpr DEAL_II_HOST_DEVICE Tensor &
720
727 template <typename OtherNumber>
728 constexpr DEAL_II_HOST_DEVICE Tensor &
729 operator*=(const OtherNumber &factor);
730
736 template <typename OtherNumber>
737 constexpr DEAL_II_HOST_DEVICE Tensor &
738 operator/=(const OtherNumber &factor);
739
746 operator-() const;
747
760 constexpr void
762
772 norm() const;
773
780 constexpr DEAL_II_HOST_DEVICE
782 norm_square() const;
783
794 template <class Iterator>
795 void
796 unroll(const Iterator begin, const Iterator end) const;
797
802 static constexpr DEAL_II_HOST_DEVICE unsigned int
804
811 unrolled_to_component_indices(const unsigned int i);
812
817 static constexpr std::size_t
819
825 template <class Archive>
826 void
827 serialize(Archive &ar, const unsigned int version);
828
834
835private:
841#if DEAL_II_KOKKOS_VERSION_GTE(3, 7, 0)
842 std::conditional_t<rank_ == 1,
843 Kokkos::Array<Number, dim>,
844 Kokkos::Array<Tensor<rank_ - 1, dim, Number>, dim>>
845#else
846 std::conditional_t<rank_ == 1,
847 std::array<Number, dim>,
848 std::array<Tensor<rank_ - 1, dim, Number>, dim>>
849#endif
851
858 template <typename ArrayLike, std::size_t... Indices>
859 constexpr DEAL_II_HOST_DEVICE
860 Tensor(const ArrayLike &initializer, std::index_sequence<Indices...>);
861
862 // Allow an arbitrary Tensor to access the underlying values.
863 template <int, int, typename>
864 friend class Tensor;
865
866 // Point is allowed access to the coordinates. This is supposed to improve
867 // speed.
868 friend class Point<dim, Number>;
869};
870
871
872#ifndef DOXYGEN
873namespace internal
874{
875 // Workaround: The following 4 overloads are necessary to be able to
876 // compile the library with Apple Clang 8 and older. We should remove
877 // these overloads again when we bump the minimal required version to
878 // something later than clang-3.6 / Apple Clang 6.3.
879 template <int rank, int dim, typename T, typename U>
880 struct ProductTypeImpl<Tensor<rank, dim, T>, std::complex<U>>
881 {
882 using type =
884 };
885
886 template <int rank, int dim, typename T, typename U>
887 struct ProductTypeImpl<Tensor<rank, dim, std::complex<T>>, std::complex<U>>
888 {
889 using type =
891 };
892
893 template <typename T, int rank, int dim, typename U>
894 struct ProductTypeImpl<std::complex<T>, Tensor<rank, dim, U>>
895 {
896 using type =
898 };
899
900 template <int rank, int dim, typename T, typename U>
901 struct ProductTypeImpl<std::complex<T>, Tensor<rank, dim, std::complex<U>>>
902 {
903 using type =
905 };
906 // end workaround
907
912 template <int rank, int dim, typename T>
913 struct NumberType<Tensor<rank, dim, T>>
914 {
915 static constexpr DEAL_II_HOST_DEVICE_ALWAYS_INLINE const
918 {
919 return t;
920 }
921
923 value(const T &t)
924 {
926 tmp = t;
927 return tmp;
928 }
929 };
930} // namespace internal
931
932
933/*---------------------- Inline functions: Tensor<0,dim> ---------------------*/
934
935
936template <int dim, typename Number>
939 // Some auto-differentiable numbers need explicit
940 // zero initialization such as adtl::adouble.
941 : Tensor{0.0}
942{}
943
944
945
946template <int dim, typename Number>
947template <typename OtherNumber>
949Tensor<0, dim, Number>::Tensor(const OtherNumber &initializer)
950 : value(internal::NumberType<Number>::value(initializer))
951{}
952
953
954
955template <int dim, typename Number>
956template <typename OtherNumber>
959 : Tensor{p.value}
960{}
961
962
963# ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
964template <int dim, typename Number>
967 : value{other.value}
968{}
969
970
971
972template <int dim, typename Number>
975 : value{std::move(other.value)}
976{}
977# endif
978
979
980
981template <int dim, typename Number>
984{
985 Assert(dim != 0,
986 ExcMessage("Cannot access an object of type Tensor<0,0,Number>"));
987 return value;
988}
989
990
991template <int dim, typename Number>
992constexpr inline DEAL_II_ALWAYS_INLINE
994{
995 Assert(dim != 0,
996 ExcMessage("Cannot access an object of type Tensor<0,0,Number>"));
997 return value;
998}
999
1000
1001
1002template <int dim, typename Number>
1003template <typename OtherNumber>
1006{
1008 return *this;
1009}
1010
1011
1012# if defined(__INTEL_COMPILER) || defined(DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG)
1013template <int dim, typename Number>
1016{
1017 value = p.value;
1018 return *this;
1019}
1020# endif
1021
1022# ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
1023template <int dim, typename Number>
1026{
1027 value = std::move(other.value);
1028 return *this;
1029}
1030# endif
1031
1032
1033
1034template <int dim, typename Number>
1035template <typename OtherNumber>
1037Tensor<0, dim, Number>::operator=(const OtherNumber &d) &
1038{
1040 return *this;
1041}
1042
1043
1044template <int dim, typename Number>
1045template <typename OtherNumber>
1046constexpr inline bool
1048{
1049# ifdef DEAL_II_ADOLC_WITH_ADVANCED_BRANCHING
1050 Assert(!(std::is_same_v<Number, adouble> ||
1051 std::is_same_v<OtherNumber, adouble>),
1052 ExcMessage(
1053 "The Tensor equality operator for ADOL-C taped numbers has not yet "
1054 "been extended to support advanced branching."));
1055# endif
1056
1057 return numbers::values_are_equal(value, p.value);
1058}
1059
1060
1061template <int dim, typename Number>
1062template <typename OtherNumber>
1063constexpr bool
1065{
1066 return !((*this) == p);
1067}
1068
1069
1070template <int dim, typename Number>
1071template <typename OtherNumber>
1074{
1075 value += p.value;
1076 return *this;
1077}
1078
1079
1080template <int dim, typename Number>
1081template <typename OtherNumber>
1084{
1085 value -= p.value;
1086 return *this;
1087}
1088
1089
1090
1091namespace internal
1092{
1093 namespace ComplexWorkaround
1094 {
1095 template <typename Number, typename OtherNumber>
1097 multiply_assign_scalar(Number &val, const OtherNumber &s)
1098 {
1099 val *= s;
1100 }
1101
1102 template <typename Number, typename OtherNumber>
1104 multiply_assign_scalar(std::complex<Number> &val, const OtherNumber &s)
1105 {
1106# if DEAL_II_KOKKOS_VERSION_GTE(3, 6, 0)
1107 KOKKOS_IF_ON_HOST((val *= s;))
1108 KOKKOS_IF_ON_DEVICE(({
1109 (void)val;
1110 (void)s;
1111 Kokkos::abort(
1112 "This function is not implemented for std::complex<Number>!\n");
1113 }))
1114# else
1115 // We do not support device code for Kokkos < 3.7:
1116 val *= s;
1117# endif
1118 }
1119 } // namespace ComplexWorkaround
1120} // namespace internal
1121
1122
1123template <int dim, typename Number>
1124template <typename OtherNumber>
1126Tensor<0, dim, Number>::operator*=(const OtherNumber &s)
1127{
1128 internal::ComplexWorkaround::multiply_assign_scalar(value, s);
1129 return *this;
1130}
1131
1132
1133
1134template <int dim, typename Number>
1135template <typename OtherNumber>
1137Tensor<0, dim, Number>::operator/=(const OtherNumber &s)
1138{
1139 value /= s;
1140 return *this;
1141}
1142
1143
1144template <int dim, typename Number>
1147{
1148 return -value;
1149}
1150
1151
1152template <int dim, typename Number>
1155{
1156 Assert(dim != 0,
1157 ExcMessage("Cannot access an object of type Tensor<0,0,Number>"));
1159}
1160
1161
1162template <int dim, typename Number>
1166{
1167 Assert(dim != 0,
1168 ExcMessage("Cannot access an object of type Tensor<0,0,Number>"));
1170}
1171
1172
1173
1174template <int dim, typename Number>
1175constexpr inline void
1177{
1178 // Some auto-differentiable numbers need explicit
1179 // zero initialization.
1181}
1182
1183
1184
1185template <int dim, typename Number>
1186template <class Iterator>
1187inline void
1188Tensor<0, dim, Number>::unroll(const Iterator begin, const Iterator end) const
1189{
1190 AssertDimension(std::distance(begin, end), n_independent_components);
1191 Assert(dim != 0,
1192 ExcMessage("Cannot unroll an object of type Tensor<0,0,Number>"));
1193 Assert(std::distance(begin, end) >= 1,
1194 ExcMessage("The provided iterator range must contain at least one "
1195 "element."));
1196 *begin = value;
1197}
1198
1199
1200
1201template <int dim, typename Number>
1202template <class Archive>
1203inline void
1204Tensor<0, dim, Number>::serialize(Archive &ar, const unsigned int)
1205{
1206 ar &value;
1207}
1208
1209
1210template <int dim, typename Number>
1212
1213
1214/*-------------------- Inline functions: Tensor<rank,dim> --------------------*/
1215
1216template <int rank_, int dim, typename Number>
1217template <typename ArrayLike, std::size_t... indices>
1219Tensor<rank_, dim, Number>::Tensor(const ArrayLike &initializer,
1220 std::index_sequence<indices...>)
1221 // Extract from the 'initializer' a sequence of elements via template
1222 // pack evaluation. This could be as easy as
1223 // values{{ (initializer[indices])... }}
1224 // but of course in practice it is not. The challenge is that if rank>1,
1225 // we want to pass the elements initializer[indices] down to the next
1226 // lower rank tensor for evaluation unchanged. But at the rank==1 level,
1227 // we need to convert to the scalar type 'Number'. This would all be
1228 // relatively straightforward if we could rely on automatic type
1229 // conversion, but for some autodifferentiation types, the conversion
1230 // from the AD to double (i.e., the extraction of a scalar value) is
1231 // not implicit, and we need to call internal::NumberType<Number>::value() --
1232 // but as mentioned, we can only do that for rank==1.
1233 //
1234 // We can achieve all of this by dispatching to a lambda function within
1235 // which we can use a 'if constexpr'.
1236 : values{{([&initializer]() -> value_type {
1237 if constexpr (rank_ == 1)
1238 return internal::NumberType<Number>::value(initializer[indices]);
1239 else
1240 return value_type(initializer[indices]);
1241 }())...}}
1242{
1243 static_assert(sizeof...(indices) == dim,
1244 "dim should match the number of indices");
1245}
1246
1247
1248# if defined(DEAL_II_HAVE_CXX20) && !defined(__NVCC__)
1249
1250template <int rank_, int dim, typename Number>
1253 : values(
1254 // In order to initialize the Kokkos::Array<Number,dim>, we would need a
1255 // brace-enclosed list of length 'dim'. There is no way in C++ to create
1256 // such a list in-place, but we can come up with a lambda function that
1257 // expands such a list via template-pack expansion, and then uses this
1258 // list to initialize a Kokkos::Array which it then returns.
1259 //
1260 // The trick to come up with such a lambda function is to have a function
1261 // that takes an argument that depends on a template-pack of integers.
1262 // We will call the function with an integer list of length 'dim', and
1263 // in the function itself expand that pack in a way that it serves as
1264 // a brace-enclosed list of initializers for a Kokkos::Array.
1265 //
1266 // Of course, we do not want to initialize the array with the integers,
1267 // but with zeros. (Or, more correctly, a zero of the element type.)
1268 // The canonical way to do this would be using the comma operator:
1269 // (sequence_element, 0.0)
1270 // returns zero, and
1271 // (sequence, 0.0)...
1272 // returns a list of zeros of the right length. Unfortunately, some
1273 // compilers then warn that the left side of the comma expression has
1274 // no effect -- well, bummer, that was of course exactly the idea.
1275 // We could work around this by using
1276 // (sequence_element * 0.0)
1277 // instead, assuming that the compiler will optimize (known) integer
1278 // times zero to zero, and similarly for (known) integer times times
1279 // default-initialized tensor.
1280 //
1281 // But, instead of relying on compiler optimizations, a better way is
1282 // to simply have another (nested) lambda function that takes the
1283 // integer sequence element as an argument and ignores it, just
1284 // returning a zero instead.
1285 []<std::size_t... I>(
1286 const std::index_sequence<I...> &) constexpr -> decltype(values) {
1287 if constexpr (dim == 0)
1288 {
1289 return {};
1290 }
1291 else if constexpr (rank_ == 1)
1292 {
1293 auto get_zero_and_ignore_argument = [](int) {
1295 };
1296 return {{(get_zero_and_ignore_argument(I))...}};
1297 }
1298 else
1299 {
1300 auto get_zero_and_ignore_argument = [](int) {
1301 return Tensor<rank_ - 1, dim, Number>();
1302 };
1303 return {{(get_zero_and_ignore_argument(I))...}};
1304 }
1305 }(std::make_index_sequence<dim>()))
1306{}
1307
1308# else
1309
1310// The C++17 case works in essence the same, except that we can't use a
1311// lambda function with explicit template parameters, i.e., we can't do
1312// []<std::size_t... I>(const std::index_sequence<I...> &)
1313// as above because that's a C++20 feature. Lambda functions in C++17 can
1314// have template packs as arguments, but we need the ability to *name*
1315// that template pack (the 'I' above) and that's not possible in C++17.
1316//
1317// We work around this by moving the lambda function to a global function
1318// and using the traditional template syntax on it.
1319namespace internal
1320{
1321 namespace TensorInitialization
1322 {
1323 template <int rank, int dim, typename Number, std::size_t... I>
1324# if DEAL_II_KOKKOS_VERSION_GTE(3, 7, 0)
1325 constexpr Kokkos::Array<typename Tensor<rank, dim, Number>::value_type, dim>
1326# else
1327 constexpr std::array<typename Tensor<rank, dim, Number>::value_type, dim>
1328# endif
1329 make_zero_array(const std::index_sequence<I...> &)
1330 {
1331 static_assert(sizeof...(I) == dim, "This is bad.");
1332
1333 // First peel off the case dim==0. If we don't, some compilers
1334 // will warn below that we define these lambda functions but
1335 // never use them (because the expanded list has zero elements,
1336 // and the get_zero_and_ignore_argument() function is not used...)
1337 if constexpr (dim == 0)
1338 {
1339 return {};
1340 }
1341 else if constexpr (rank == 1)
1342 {
1343 auto get_zero_and_ignore_argument = [](int) {
1345 };
1346 return {{(get_zero_and_ignore_argument(I))...}};
1347 }
1348 else
1349 {
1350 auto get_zero_and_ignore_argument = [](int) {
1351 return Tensor<rank - 1, dim, Number>();
1352 };
1353 return {{(get_zero_and_ignore_argument(I))...}};
1354 }
1355 }
1356 } // namespace TensorInitialization
1357} // namespace internal
1358
1359
1360template <int rank_, int dim, typename Number>
1363 : values(internal::TensorInitialization::make_zero_array<rank_, dim, Number>(
1364 std::make_index_sequence<dim>()))
1365{}
1366
1367
1368# endif
1369
1370
1371template <int rank_, int dim, typename Number>
1373Tensor<rank_, dim, Number>::Tensor(const array_type &initializer)
1374 : Tensor(initializer, std::make_index_sequence<dim>{})
1375{}
1376
1377
1378
1379template <int rank_, int dim, typename Number>
1380template <typename ElementType, typename MemorySpace>
1383 const ArrayView<ElementType, MemorySpace> &initializer)
1384{
1385 // make nvcc happy
1386 const int my_n_independent_components = n_independent_components;
1387 AssertDimension(initializer.size(), my_n_independent_components);
1388
1389 for (unsigned int i = 0; i < my_n_independent_components; ++i)
1390 (*this)[unrolled_to_component_indices(i)] = initializer[i];
1391}
1392
1393
1394
1395template <int rank_, int dim, typename Number>
1396template <typename OtherNumber>
1399 const Tensor<rank_, dim, OtherNumber> &initializer)
1400 : Tensor(initializer, std::make_index_sequence<dim>{})
1401{}
1402
1403
1404
1405template <int rank_, int dim, typename Number>
1406template <typename OtherNumber>
1407constexpr DEAL_II_ALWAYS_INLINE
1409 const Tensor<1, dim, Tensor<rank_ - 1, dim, OtherNumber>> &initializer)
1410 : Tensor(initializer, std::make_index_sequence<dim>{})
1411{}
1412
1413
1414
1415template <int rank_, int dim, typename Number>
1416template <typename OtherNumber>
1418operator Tensor<1, dim, Tensor<rank_ - 1, dim, OtherNumber>>() const
1419{
1420 Tensor<1, dim, Tensor<rank_ - 1, dim, OtherNumber>> x;
1421 std::copy(values.data(), values.data() + values.size(), x.values.data());
1422 return x;
1423}
1424
1425
1426# ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
1427template <int rank_, int dim, typename Number>
1428constexpr DEAL_II_ALWAYS_INLINE
1430 : values(other.values)
1431{}
1432
1433
1434
1435template <int rank_, int dim, typename Number>
1436constexpr DEAL_II_ALWAYS_INLINE
1438 : values(std::move(other.values))
1439{}
1440# endif
1441
1442
1443
1444template <int rank_, int dim, typename Number>
1447 Tensor<rank_, dim, Number>::operator[](const unsigned int i)
1448{
1449 Assert(dim != 0,
1450 ExcMessage("Cannot access an object of type Tensor<rank_,0,Number>"));
1451 AssertIndexRange(i, dim);
1452 DEAL_II_CXX23_ASSUME(i < dim);
1453
1454 return values[i];
1455}
1456
1457
1458template <int rank_, int dim, typename Number>
1459constexpr DEAL_II_ALWAYS_INLINE
1461 Tensor<rank_, dim, Number>::operator[](const unsigned int i) const
1462{
1463 Assert(dim != 0,
1464 ExcMessage("Cannot access an object of type Tensor<rank_,0,Number>"));
1465 AssertIndexRange(i, dim);
1466 DEAL_II_CXX23_ASSUME(i < dim);
1467
1468 return values[i];
1469}
1470
1471
1472template <int rank_, int dim, typename Number>
1473constexpr inline DEAL_II_ALWAYS_INLINE const Number &
1475{
1476 Assert(dim != 0,
1477 ExcMessage("Cannot access an object of type Tensor<rank_,0,Number>"));
1478
1479 return TensorAccessors::extract<rank_>(*this, indices);
1480}
1481
1482
1483
1484template <int rank_, int dim, typename Number>
1485constexpr inline DEAL_II_ALWAYS_INLINE Number &
1487{
1488 Assert(dim != 0,
1489 ExcMessage("Cannot access an object of type Tensor<rank_,0,Number>"));
1490
1491 return TensorAccessors::extract<rank_>(*this, indices);
1492}
1493
1494
1495
1496template <int rank_, int dim, typename Number>
1497inline Number *
1499{
1500 static_assert(rank_ == 1,
1501 "This function is only available for rank-1 tensors "
1502 "because higher-rank tensors may not store their elements "
1503 "in a contiguous array.");
1504
1505 return std::addressof(
1506 this->operator[](this->unrolled_to_component_indices(0)));
1507}
1508
1509
1510
1511template <int rank_, int dim, typename Number>
1512inline const Number *
1514{
1515 static_assert(rank_ == 1,
1516 "This function is only available for rank-1 tensors "
1517 "because higher-rank tensors may not store their elements "
1518 "in a contiguous array.");
1519
1520 return std::addressof(
1521 this->operator[](this->unrolled_to_component_indices(0)));
1522}
1523
1524
1525
1526template <int rank_, int dim, typename Number>
1527inline Number *
1529{
1530 static_assert(rank_ == 1,
1531 "This function is only available for rank-1 tensors "
1532 "because higher-rank tensors may not store their elements "
1533 "in a contiguous array.");
1534
1535 return begin_raw() + n_independent_components;
1536}
1537
1538
1539
1540template <int rank_, int dim, typename Number>
1541inline const Number *
1543{
1544 static_assert(rank_ == 1,
1545 "This function is only available for rank-1 tensors "
1546 "because higher-rank tensors may not store their elements "
1547 "in a contiguous array.");
1548
1549 return begin_raw() + n_independent_components;
1550}
1551
1552
1553
1554template <int rank_, int dim, typename Number>
1555template <typename OtherNumber>
1558{
1559 // The following loop could be written more concisely using std::copy, but
1560 // that function is only constexpr from C++20 on.
1561 for (unsigned int i = 0; i < dim; ++i)
1562 values[i] = t.values[i];
1563 return *this;
1564}
1565
1566
1567
1568template <int rank_, int dim, typename Number>
1571 Tensor<rank_, dim, Number>::operator=(const Number &d) &
1572{
1574
1575 for (unsigned int i = 0; i < dim; ++i)
1576 values[i] = internal::NumberType<Number>::value(0.0);
1577 return *this;
1578}
1579
1580
1581# ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
1582template <int rank_, int dim, typename Number>
1585{
1586 for (unsigned int i = 0; i < dim; ++i)
1587 values[i] = other.values[i];
1588 return *this;
1589}
1590
1591
1592
1593template <int rank_, int dim, typename Number>
1596 Tensor<rank_, dim, Number> &&other) noexcept
1597{
1598 for (unsigned int i = 0; i < dim; ++i)
1599 values[i] = other.values[i];
1600 return *this;
1601}
1602# endif
1603
1604
1605template <int rank_, int dim, typename Number>
1606template <typename OtherNumber>
1607constexpr inline bool
1609 const Tensor<rank_, dim, OtherNumber> &p) const
1610{
1611# ifdef DEAL_II_ADOLC_WITH_ADVANCED_BRANCHING
1612 Assert(!(std::is_same_v<Number, adouble> ||
1613 std::is_same_v<OtherNumber, adouble>),
1614 ExcMessage(
1615 "The Tensor equality operator for ADOL-C taped numbers has not yet "
1616 "been extended to support advanced branching."));
1617# endif
1618
1619 for (unsigned int i = 0; i < dim; ++i)
1620 if (numbers::values_are_not_equal(values[i], p.values[i]))
1621 return false;
1622 return true;
1623}
1624
1625
1626// At some places in the library, we have Point<0> for formal reasons
1627// (e.g., we sometimes have Quadrature<dim-1> for faces, so we have
1628// Quadrature<0> for dim=1, and then we have Point<0>). To avoid warnings
1629// in the above function that the loop end check always fails, we
1630// implement this function here
1631template <>
1632template <>
1633constexpr inline bool
1635{
1636 return true;
1637}
1638
1639
1640template <int rank_, int dim, typename Number>
1641template <typename OtherNumber>
1642constexpr bool
1644 const Tensor<rank_, dim, OtherNumber> &p) const
1645{
1646 return !((*this) == p);
1647}
1648
1649
1650template <int rank_, int dim, typename Number>
1651template <typename OtherNumber>
1652constexpr inline DEAL_II_ALWAYS_INLINE
1656{
1657 for (unsigned int i = 0; i < dim; ++i)
1658 values[i] += p.values[i];
1659 return *this;
1660}
1661
1662
1663template <int rank_, int dim, typename Number>
1664template <typename OtherNumber>
1665constexpr inline DEAL_II_ALWAYS_INLINE
1669{
1670 for (unsigned int i = 0; i < dim; ++i)
1671 values[i] -= p.values[i];
1672 return *this;
1673}
1674
1675
1676template <int rank_, int dim, typename Number>
1677template <typename OtherNumber>
1678constexpr inline DEAL_II_ALWAYS_INLINE
1680 Tensor<rank_, dim, Number>::operator*=(const OtherNumber &s)
1681{
1682 for (unsigned int i = 0; i < dim; ++i)
1683 values[i] *= s;
1684 return *this;
1685}
1686
1687
1688
1689template <int rank_, int dim, typename Number>
1690template <typename OtherNumber>
1691constexpr inline DEAL_II_ALWAYS_INLINE
1693 Tensor<rank_, dim, Number>::operator/=(const OtherNumber &s)
1694{
1695 if constexpr (std::is_integral_v<
1697 std::is_same_v<Number, Differentiation::SD::Expression>)
1698 {
1699 // recurse over the base objects
1700 for (unsigned int d = 0; d < dim; ++d)
1701 values[d] /= s;
1702 }
1703 else
1704 {
1705 // If we can, avoid division by multiplying by the inverse of the given
1706 // factor:
1707 const Number inverse_factor = Number(1.) / s;
1708 for (unsigned int d = 0; d < dim; ++d)
1709 values[d] *= inverse_factor;
1710 }
1711
1712 return *this;
1713}
1714
1715
1716template <int rank_, int dim, typename Number>
1717constexpr inline DEAL_II_ALWAYS_INLINE
1720{
1722
1723 for (unsigned int i = 0; i < dim; ++i)
1724 tmp.values[i] = -values[i];
1725
1726 return tmp;
1727}
1728
1729
1730template <int rank_, int dim, typename Number>
1733{
1734 // Handle cases of a tensor consisting of just one number more
1735 // efficiently:
1736 if constexpr ((rank_ == 1) && (dim == 1) && std::is_arithmetic_v<Number>)
1737 {
1738 return std::abs(values[0]);
1739 }
1740 else if constexpr ((rank_ == 2) && (dim == 1) && std::is_arithmetic_v<Number>)
1741 {
1742 return std::abs(values[0][0]);
1743 }
1744 else
1745 {
1746 // Otherwise fall back to the naive algorithm of taking the square root of
1747 // the sum of squares.
1748
1749 // Make things work with AD types by letting the compiler look up
1750 // the symbol sqrt in namespace std and in the type-associated
1751 // namespaces
1752 using std::sqrt;
1753 return sqrt(norm_square());
1754 }
1755}
1756
1757
1758template <int rank_, int dim, typename Number>
1762{
1763 if constexpr (dim == 0)
1764 return internal::NumberType<
1765 typename numbers::NumberTraits<Number>::real_type>::value(0.0);
1766 else if constexpr (rank_ == 1)
1767 {
1768 // For rank-1 tensors, the square of the norm is simply the sum of
1769 // squares of the elements:
1772 for (unsigned int i = 1; i < dim; ++i)
1774
1775 return s;
1776 }
1777 else
1778 {
1779 // For higher-rank tensors, the square of the norm is the sum
1780 // of squares of sub-tensors
1782 values[0].norm_square();
1783 for (unsigned int i = 1; i < dim; ++i)
1784 s += values[i].norm_square();
1785
1786 return s;
1787 }
1788}
1789
1790
1791
1792template <int rank_, int dim, typename Number>
1793template <class Iterator>
1794inline void
1796 const Iterator end) const
1797{
1798 if constexpr (rank_ > 1)
1799 {
1800 // For higher-rank tensors, we recurse to the sub-tensors:
1801 Iterator next = begin;
1802 for (unsigned int i = 0; i < dim; ++i)
1803 {
1804 values[i].unroll(next, end);
1805 std::advance(
1807 }
1808 }
1809 else
1810 {
1811 // For rank-1 tensors, we can simply copy the current elements from
1812 // our linear array into the output range:
1813 Assert(std::distance(begin, end) >= dim,
1814 ExcMessage(
1815 "The provided iterator range must contain at least 'dim' "
1816 "elements."));
1817 std::copy(values.data(), values.data() + values.size(), begin);
1818 }
1819}
1820
1821
1822
1823template <int rank_, int dim, typename Number>
1824constexpr inline unsigned int
1826 const TableIndices<rank_> &indices)
1827{
1828 unsigned int index = 0;
1829 for (int r = 0; r < rank_; ++r)
1830 index = index * dim + indices[r];
1831
1832 return index;
1833}
1834
1835
1836
1837template <int rank_, int dim, typename Number>
1838constexpr inline TableIndices<rank_>
1840{
1841 // Work-around nvcc warning
1842 unsigned int dummy = n_independent_components;
1843 AssertIndexRange(i, dummy);
1844
1845 if constexpr (dim == 0)
1846 {
1847 Assert(false,
1848 ExcMessage(
1849 "A tensor with dimension 0 does not store any elements. "
1850 "There is no indexing that can address its elements."));
1851 return {};
1852 }
1853 else
1854 {
1855 TableIndices<rank_> indices;
1856
1857 unsigned int remainder = i;
1858 for (int r = rank_ - 1; r >= 0; --r)
1859 {
1860 indices[r] = remainder % dim;
1861 remainder = remainder / dim;
1862 }
1863 Assert(remainder == 0, ExcInternalError());
1864
1865 return indices;
1866 }
1867}
1868
1869
1870template <int rank_, int dim, typename Number>
1871constexpr inline void
1873{
1874 for (unsigned int i = 0; i < dim; ++i)
1875 values[i] = internal::NumberType<Number>::value(0.0);
1876}
1877
1878
1879template <int rank_, int dim, typename Number>
1880constexpr std::size_t
1882{
1883 return sizeof(Tensor<rank_, dim, Number>);
1884}
1885
1886
1887template <int rank_, int dim, typename Number>
1888template <class Archive>
1889inline void
1890Tensor<rank_, dim, Number>::serialize(Archive &ar, const unsigned int)
1891{
1892 for (int i = 0; i < dim; ++i)
1893 {
1894 ar &values[i];
1895 }
1896}
1897
1898
1899template <int rank_, int dim, typename Number>
1901
1902#endif // DOXYGEN
1903
1904/* ----------------- Non-member functions operating on tensors. ------------ */
1905
1918template <int rank_, int dim, typename Number>
1919inline std::ostream &
1920operator<<(std::ostream &out, const Tensor<rank_, dim, Number> &p)
1921{
1922 for (unsigned int i = 0; i < dim; ++i)
1923 {
1924 out << p[i];
1925 if (i != dim - 1)
1926 for (unsigned int j = 0; j < rank_; ++j)
1927 out << ' ';
1928 }
1929
1930 return out;
1931}
1932
1933
1940template <int dim, typename Number>
1941inline std::ostream &
1942operator<<(std::ostream &out, const Tensor<0, dim, Number> &p)
1943{
1944 out << static_cast<const Number &>(p);
1945 return out;
1946}
1947
1948
1967template <int dim, typename Number, typename Other>
1970 operator*(const Other &object, const Tensor<0, dim, Number> &t)
1971{
1972 return object * static_cast<const Number &>(t);
1973}
1974
1975
1976
1987template <int dim, typename Number, typename Other>
1990 operator*(const Tensor<0, dim, Number> &t, const Other &object)
1991{
1992 return static_cast<const Number &>(t) * object;
1993}
1994
1995
2007template <int dim, typename Number, typename OtherNumber>
2011 const Tensor<0, dim, OtherNumber> &src2)
2012{
2013 return static_cast<const Number &>(src1) *
2014 static_cast<const OtherNumber &>(src2);
2015}
2016
2017
2025template <int dim, typename Number, typename OtherNumber>
2027 Tensor<0,
2028 dim,
2029 typename ProductType<Number,
2030 typename EnableIfScalar<OtherNumber>::type>::type>
2031 operator/(const Tensor<0, dim, Number> &t, const OtherNumber &factor)
2032{
2033 return static_cast<const Number &>(t) / factor;
2034}
2035
2036
2044template <int dim, typename Number, typename OtherNumber>
2049{
2050 return static_cast<const Number &>(p) + static_cast<const OtherNumber &>(q);
2051}
2052
2053
2061template <int dim, typename Number, typename OtherNumber>
2066{
2067 return static_cast<const Number &>(p) - static_cast<const OtherNumber &>(q);
2068}
2069
2070
2083template <int rank, int dim, typename Number, typename OtherNumber>
2085 Tensor<rank,
2086 dim,
2087 typename ProductType<Number,
2088 typename EnableIfScalar<OtherNumber>::type>::type>
2089 operator*(const Tensor<rank, dim, Number> &t, const OtherNumber &factor)
2090{
2092 tt *= factor;
2093 return tt;
2094}
2095
2096
2109template <int rank, int dim, typename Number, typename OtherNumber>
2111 Tensor<rank,
2112 dim,
2114 OtherNumber>::type>
2115 operator*(const Number &factor, const Tensor<rank, dim, OtherNumber> &t)
2116{
2117 // simply forward to the operator above
2118 return t * factor;
2119}
2120
2121
2122
2132template <int rank, int dim, typename Number, typename OtherNumber>
2134 Tensor<rank,
2135 dim,
2136 typename ProductType<Number,
2137 typename EnableIfScalar<OtherNumber>::type>::type>
2138 operator/(const Tensor<rank, dim, Number> &t, const OtherNumber &factor)
2139{
2141 tt /= factor;
2142 return tt;
2143}
2144
2145
2155template <int rank, int dim, typename Number, typename OtherNumber>
2165
2166
2176template <int rank, int dim, typename Number, typename OtherNumber>
2186
2193template <int dim, typename Number, typename OtherNumber>
2194inline constexpr DEAL_II_ALWAYS_INLINE
2197 const Tensor<0, dim, OtherNumber> &src2)
2198{
2200
2201 tmp *= src2;
2202
2203 return tmp;
2204}
2205
2222template <int rank, int dim, typename Number, typename OtherNumber>
2223inline constexpr DEAL_II_ALWAYS_INLINE
2227{
2229
2230 for (unsigned int i = 0; i < dim; ++i)
2233
2234 return tmp;
2235}
2236
2281template <int rank_1,
2282 int rank_2,
2283 int dim,
2284 typename Number,
2285 typename OtherNumber,
2286 typename = std::enable_if_t<rank_1 >= 1 && rank_2 >= 1>>
2287constexpr inline DEAL_II_ALWAYS_INLINE
2288 typename Tensor<rank_1 + rank_2 - 2,
2289 dim,
2290 typename ProductType<Number, OtherNumber>::type>::tensor_type
2293{
2294 // Treat some common cases separately. Specifically, these are the dot
2295 // product between two rank-1 tensors, and the product between a
2296 // rank-2 tensor and a rank-1 tensor. Both of these lead to a linear
2297 // loop over adjacent memory and can be dealt with efficiently; in the
2298 // latter case (rank-2 times rank-1), we implement things by deferring
2299 // to rank-1 times rank-1 dot products.
2300 if constexpr ((rank_1 == 1) && (rank_2 == 1))
2301 {
2302 // This is a dot product between two rank-1 tensors. Write it out as
2303 // a linear loop:
2304 static_assert(dim > 0, "Tensors cannot have dimension zero.");
2305 typename ProductType<Number, OtherNumber>::type sum = src1[0] * src2[0];
2306 for (unsigned int i = 1; i < dim; ++i)
2307 sum += src1[i] * src2[i];
2308
2309 return sum;
2310 }
2311 else if constexpr ((rank_1 == 2) && (rank_2 == 1))
2312 {
2313 // This is a product between a rank-2 and a rank-1 tensor. This
2314 // corresponds to taking dot products between the rows of the former
2315 // and the latter.
2316 typename Tensor<
2317 rank_1 + rank_2 - 2,
2318 dim,
2319 typename ProductType<Number, OtherNumber>::type>::tensor_type result;
2320 for (unsigned int i = 0; i < dim; ++i)
2321 result[i] += src1[i] * src2;
2322
2323 return result;
2324 }
2325 else
2326 {
2327 // Treat all of the other cases using the more general contraction
2328 // machinery.
2329 typename Tensor<
2330 rank_1 + rank_2 - 2,
2331 dim,
2332 typename ProductType<Number, OtherNumber>::type>::tensor_type result{};
2333
2334 TensorAccessors::internal::
2335 ReorderedIndexView<0, rank_2, const Tensor<rank_2, dim, OtherNumber>>
2336 reordered = TensorAccessors::reordered_index_view<0, rank_2>(src2);
2337 TensorAccessors::contract<1, rank_1, rank_2, dim>(result,
2338 src1,
2339 reordered);
2340
2341 return result;
2342 }
2343}
2344
2345
2374template <int index_1,
2375 int index_2,
2376 int rank_1,
2377 int rank_2,
2378 int dim,
2379 typename Number,
2380 typename OtherNumber>
2381constexpr inline DEAL_II_ALWAYS_INLINE
2382 typename Tensor<rank_1 + rank_2 - 2,
2383 dim,
2384 typename ProductType<Number, OtherNumber>::type>::tensor_type
2387{
2388 Assert(0 <= index_1 && index_1 < rank_1,
2389 ExcMessage(
2390 "The specified index_1 must lie within the range [0,rank_1)"));
2391 Assert(0 <= index_2 && index_2 < rank_2,
2392 ExcMessage(
2393 "The specified index_2 must lie within the range [0,rank_2)"));
2394
2395 using namespace TensorAccessors;
2396 using namespace TensorAccessors::internal;
2397
2398 // Reorder index_1 to the end of src1:
2400 reord_01 = reordered_index_view<index_1, rank_1>(src1);
2401
2402 // Reorder index_2 to the end of src2:
2403 const ReorderedIndexView<index_2,
2404 rank_2,
2406 reord_02 = reordered_index_view<index_2, rank_2>(src2);
2407
2408 typename Tensor<rank_1 + rank_2 - 2,
2409 dim,
2410 typename ProductType<Number, OtherNumber>::type>::tensor_type
2411 result{};
2412 TensorAccessors::contract<1, rank_1, rank_2, dim>(result, reord_01, reord_02);
2413 return result;
2414}
2415
2416
2447template <int index_1,
2448 int index_2,
2449 int index_3,
2450 int index_4,
2451 int rank_1,
2452 int rank_2,
2453 int dim,
2454 typename Number,
2455 typename OtherNumber>
2456constexpr inline
2457 typename Tensor<rank_1 + rank_2 - 4,
2458 dim,
2459 typename ProductType<Number, OtherNumber>::type>::tensor_type
2460 double_contract(const Tensor<rank_1, dim, Number> &src1,
2462{
2463 Assert(0 <= index_1 && index_1 < rank_1,
2464 ExcMessage(
2465 "The specified index_1 must lie within the range [0,rank_1)"));
2466 Assert(0 <= index_3 && index_3 < rank_1,
2467 ExcMessage(
2468 "The specified index_3 must lie within the range [0,rank_1)"));
2469 Assert(index_1 != index_3,
2470 ExcMessage("index_1 and index_3 must not be the same"));
2471 Assert(0 <= index_2 && index_2 < rank_2,
2472 ExcMessage(
2473 "The specified index_2 must lie within the range [0,rank_2)"));
2474 Assert(0 <= index_4 && index_4 < rank_2,
2475 ExcMessage(
2476 "The specified index_4 must lie within the range [0,rank_2)"));
2477 Assert(index_2 != index_4,
2478 ExcMessage("index_2 and index_4 must not be the same"));
2479
2480 using namespace TensorAccessors;
2481 using namespace TensorAccessors::internal;
2482
2483 // Reorder index_1 to the end of src1:
2485 reord_1 = TensorAccessors::reordered_index_view<index_1, rank_1>(src1);
2486
2487 // Reorder index_2 to the end of src2:
2489 reord_2 = TensorAccessors::reordered_index_view<index_2, rank_2>(src2);
2490
2491 // Now, reorder index_3 to the end of src1. We have to make sure to
2492 // preserve the original ordering: index_1 has been removed. If
2493 // index_3 > index_1, we have to use (index_3 - 1) instead:
2495 (index_3 < index_1 ? index_3 : index_3 - 1),
2496 rank_1,
2497 ReorderedIndexView<index_1, rank_1, const Tensor<rank_1, dim, Number>>>
2498 reord_3 =
2499 TensorAccessors::reordered_index_view < index_3 < index_1 ? index_3 :
2500 index_3 - 1,
2501 rank_1 > (reord_1);
2502
2503 // Now, reorder index_4 to the end of src2. We have to make sure to
2504 // preserve the original ordering: index_2 has been removed. If
2505 // index_4 > index_2, we have to use (index_4 - 1) instead:
2507 (index_4 < index_2 ? index_4 : index_4 - 1),
2508 rank_2,
2510 reord_4 =
2511 TensorAccessors::reordered_index_view < index_4 < index_2 ? index_4 :
2512 index_4 - 1,
2513 rank_2 > (reord_2);
2514
2515 typename Tensor<rank_1 + rank_2 - 4,
2516 dim,
2517 typename ProductType<Number, OtherNumber>::type>::tensor_type
2518 result{};
2519 TensorAccessors::contract<2, rank_1, rank_2, dim>(result, reord_3, reord_4);
2520 return result;
2521}
2522
2523
2536template <int rank, int dim, typename Number, typename OtherNumber>
2537constexpr inline DEAL_II_ALWAYS_INLINE
2539 scalar_product(const Tensor<rank, dim, Number> &left,
2540 const Tensor<rank, dim, OtherNumber> &right)
2541{
2543 TensorAccessors::contract<rank, rank, rank, dim>(result, left, right);
2544 return result;
2545}
2546
2547
2565template <template <int, int, typename> class TensorT1,
2566 template <int, int, typename>
2567 class TensorT2,
2568 template <int, int, typename>
2569 class TensorT3,
2570 int rank_1,
2571 int rank_2,
2572 int dim,
2573 typename T1,
2574 typename T2,
2575 typename T3>
2576constexpr inline DEAL_II_ALWAYS_INLINE
2578 contract3(const TensorT1<rank_1, dim, T1> &left,
2579 const TensorT2<rank_1 + rank_2, dim, T2> &middle,
2580 const TensorT3<rank_2, dim, T3> &right)
2581{
2582 using return_type =
2584 return TensorAccessors::contract3<rank_1, rank_2, dim, return_type>(left,
2585 middle,
2586 right);
2587}
2588
2589
2600template <int rank_1,
2601 int rank_2,
2602 int dim,
2603 typename Number,
2604 typename OtherNumber>
2605constexpr inline DEAL_II_ALWAYS_INLINE
2609{
2610 typename Tensor<rank_1 + rank_2,
2611 dim,
2612 typename ProductType<Number, OtherNumber>::type>::tensor_type
2613 result{};
2614 TensorAccessors::contract<0, rank_1, rank_2, dim>(result, src1, src2);
2615 return result;
2616}
2617
2618
2637template <int dim, typename Number>
2639cross_product_2d(const Tensor<1, dim, Number> &src)
2640{
2641 Assert(dim == 2, ExcInternalError());
2642
2644
2645 result[0] = src[1];
2646 result[1] = -src[0];
2647
2648 return result;
2649}
2650
2651
2661template <int dim, typename Number1, typename Number2>
2662constexpr inline DEAL_II_ALWAYS_INLINE
2664 cross_product_3d(const Tensor<1, dim, Number1> &src1,
2665 const Tensor<1, dim, Number2> &src2)
2666{
2667 Assert(dim == 3, ExcInternalError());
2668
2670
2671 if constexpr (dim == 3)
2672 {
2673 result[0] = src1[1] * src2[2] - src1[2] * src2[1];
2674 result[1] = src1[2] * src2[0] - src1[0] * src2[2];
2675 result[2] = src1[0] * src2[1] - src1[1] * src2[0];
2676 }
2677
2678 return result;
2679}
2680
2681
2695template <int dim, typename Number>
2696constexpr inline DEAL_II_ALWAYS_INLINE Number
2698{
2699 // Compute the determinant using the Laplace expansion of the
2700 // determinant. We expand along the last row.
2702
2703 for (unsigned int k = 0; k < dim; ++k)
2704 {
2705 Tensor<2, dim - 1, Number> minor;
2706 for (unsigned int i = 0; i < dim - 1; ++i)
2707 for (unsigned int j = 0; j < dim - 1; ++j)
2708 minor[i][j] = t[i][j < k ? j : j + 1];
2709
2710 const Number cofactor = ((k % 2 == 0) ? -1. : 1.) * determinant(minor);
2711
2712 det += t[dim - 1][k] * cofactor;
2713 }
2714
2715 return ((dim % 2 == 0) ? 1. : -1.) * det;
2716}
2717
2723template <typename Number>
2726{
2727 return t[0][0];
2728}
2729
2735template <typename Number>
2738{
2739 // hard-coded for efficiency reasons
2740 return t[0][0] * t[1][1] - t[1][0] * t[0][1];
2741}
2742
2748template <typename Number>
2751{
2752 // hard-coded for efficiency reasons
2753 const Number C0 = internal::NumberType<Number>::value(t[1][1] * t[2][2]) -
2754 internal::NumberType<Number>::value(t[1][2] * t[2][1]);
2755 const Number C1 = internal::NumberType<Number>::value(t[1][2] * t[2][0]) -
2756 internal::NumberType<Number>::value(t[1][0] * t[2][2]);
2757 const Number C2 = internal::NumberType<Number>::value(t[1][0] * t[2][1]) -
2758 internal::NumberType<Number>::value(t[1][1] * t[2][0]);
2759 return t[0][0] * C0 + t[0][1] * C1 + t[0][2] * C2;
2760}
2761
2762
2769template <int dim, typename Number>
2770constexpr inline DEAL_II_ALWAYS_INLINE Number
2772{
2773 Number t = d[0][0];
2774 for (unsigned int i = 1; i < dim; ++i)
2775 t += d[i][i];
2776 return t;
2777}
2778
2779
2788template <int dim, typename Number>
2789constexpr inline Tensor<2, dim, Number>
2791{
2792 Number return_tensor[dim][dim];
2793
2794 // if desired, take over the
2795 // inversion of a 4x4 tensor
2796 // from the FullMatrix
2798
2799 return Tensor<2, dim, Number>(return_tensor);
2800}
2801
2802
2803#ifndef DOXYGEN
2804
2805template <typename Number>
2808{
2809 Tensor<2, 1, Number> return_tensor;
2810
2811 return_tensor[0][0] = internal::NumberType<Number>::value(1.0 / t[0][0]);
2812
2813 return return_tensor;
2814}
2815
2816
2817template <typename Number>
2820{
2821 Tensor<2, 2, Number> return_tensor;
2822
2824 1.0 / (t[0][0] * t[1][1] - t[1][0] * t[0][1]));
2825 return_tensor[0][0] = t[1][1];
2826 return_tensor[0][1] = -t[0][1];
2827 return_tensor[1][0] = -t[1][0];
2828 return_tensor[1][1] = t[0][0];
2829 return_tensor *= inv_det_t;
2830
2831 return return_tensor;
2832}
2833
2834template <typename Number>
2837{
2838 Tensor<2, 3, Number> return_tensor;
2839
2840 const auto value = [](const auto &t) {
2842 };
2843
2844 return_tensor[0][0] = value(t[1][1] * t[2][2]) - value(t[1][2] * t[2][1]);
2845 return_tensor[0][1] = value(t[0][2] * t[2][1]) - value(t[0][1] * t[2][2]);
2846 return_tensor[0][2] = value(t[0][1] * t[1][2]) - value(t[0][2] * t[1][1]);
2847 return_tensor[1][0] = value(t[1][2] * t[2][0]) - value(t[1][0] * t[2][2]);
2848 return_tensor[1][1] = value(t[0][0] * t[2][2]) - value(t[0][2] * t[2][0]);
2849 return_tensor[1][2] = value(t[0][2] * t[1][0]) - value(t[0][0] * t[1][2]);
2850 return_tensor[2][0] = value(t[1][0] * t[2][1]) - value(t[1][1] * t[2][0]);
2851 return_tensor[2][1] = value(t[0][1] * t[2][0]) - value(t[0][0] * t[2][1]);
2852 return_tensor[2][2] = value(t[0][0] * t[1][1]) - value(t[0][1] * t[1][0]);
2853
2854 const Number inv_det_t =
2855 value(1.0 / (t[0][0] * return_tensor[0][0] + t[0][1] * return_tensor[1][0] +
2856 t[0][2] * return_tensor[2][0]));
2857 return_tensor *= inv_det_t;
2858
2859 return return_tensor;
2860}
2861
2862#endif /* DOXYGEN */
2863
2864
2870template <int dim, typename Number>
2873{
2875 for (unsigned int i = 0; i < dim; ++i)
2876 {
2877 tt[i][i] = t[i][i];
2878 for (unsigned int j = i + 1; j < dim; ++j)
2879 {
2880 tt[i][j] = t[j][i];
2881 tt[j][i] = t[i][j];
2882 };
2883 }
2884 return tt;
2885}
2886
2887
2901template <int dim, typename Number>
2902constexpr Tensor<2, dim, Number>
2903adjugate(const Tensor<2, dim, Number> &t)
2904{
2905 return determinant(t) * invert(t);
2906}
2907
2908
2922template <int dim, typename Number>
2923constexpr Tensor<2, dim, Number>
2924cofactor(const Tensor<2, dim, Number> &t)
2925{
2926 return transpose(adjugate(t));
2927}
2928
2929
2993template <int dim, typename Number>
2996
2997
3005template <int dim, typename Number>
3006inline Number
3008{
3009 Number max = internal::NumberType<Number>::value(0.0);
3010 for (unsigned int j = 0; j < dim; ++j)
3011 {
3012 Number sum = internal::NumberType<Number>::value(0.0);
3013 for (unsigned int i = 0; i < dim; ++i)
3014 sum += numbers::NumberTraits<Number>::abs(t[i][j]);
3015
3016 if (sum > max)
3017 max = sum;
3018 }
3019
3020 return max;
3021}
3022
3023
3031template <int dim, typename Number>
3032inline Number
3034{
3035 Number max = internal::NumberType<Number>::value(0.0);
3036 for (unsigned int i = 0; i < dim; ++i)
3037 {
3038 Number sum = internal::NumberType<Number>::value(0.0);
3039 for (unsigned int j = 0; j < dim; ++j)
3040 sum += numbers::NumberTraits<Number>::abs(t[i][j]);
3041
3042 if (sum > max)
3043 max = sum;
3044 }
3045
3046 return max;
3047}
3048
3054#ifndef DOXYGEN
3055
3056
3057# ifdef DEAL_II_ADOLC_WITH_ADVANCED_BRANCHING
3058
3059// Specialization of functions for ADOL-C number types when
3060// the advanced branching feature is used
3061template <int dim>
3062inline adouble
3064{
3065 adouble max = internal::NumberType<adouble>::value(0.0);
3066 for (unsigned int j = 0; j < dim; ++j)
3067 {
3068 adouble sum = internal::NumberType<adouble>::value(0.0);
3069 for (unsigned int i = 0; i < dim; ++i)
3070 sum += fabs(t[i][j]);
3071
3072 condassign(max, (sum > max), sum, max);
3073 }
3074
3075 return max;
3076}
3077
3078
3079template <int dim>
3080inline adouble
3082{
3084 for (unsigned int i = 0; i < dim; ++i)
3085 {
3087 for (unsigned int j = 0; j < dim; ++j)
3088 sum += fabs(t[i][j]);
3089
3090 condassign(max, (sum > max), sum, max);
3091 }
3092
3093 return max;
3094}
3095
3096# endif // DEAL_II_ADOLC_WITH_ADVANCED_BRANCHING
3097
3098
3099#endif // DOXYGEN
3100
3102
3103#endif
*  iterator end()
*  *  iterator begin()
*  *  reference operator*() const
std::size_t size() const
Definition array_view.h:737
Definition point.h:111
constexpr Tensor & operator*=(const OtherNumber &factor)
constexpr Tensor & operator=(const OtherNumber &d) &&=delete
void serialize(Archive &ar, const unsigned int version)
constexpr Tensor & operator/=(const OtherNumber &factor)
constexpr Tensor & operator-=(const Tensor< 0, dim, OtherNumber > &rhs)
constexpr Tensor(const Tensor< 0, dim, OtherNumber > &initializer)
constexpr Tensor(const OtherNumber &initializer)
constexpr void clear()
constexpr real_type norm_square() const
constexpr bool operator!=(const Tensor< 0, dim, OtherNumber > &rhs) const
constexpr Tensor & operator=(const Tensor< 0, dim, OtherNumber > &rhs)
real_type norm() const
constexpr Tensor & operator+=(const Tensor< 0, dim, OtherNumber > &rhs)
void unroll(const Iterator begin, const Iterator end) const
constexpr bool operator==(const Tensor< 0, dim, OtherNumber > &rhs) const
typename numbers::NumberTraits< Number >::real_type real_type
Definition tensor.h:127
constexpr Tensor & operator=(const OtherNumber &d) &
constexpr Tensor operator-() const
constexpr Tensor & operator/=(const OtherNumber &factor)
constexpr Tensor(const ArrayView< ElementType, MemorySpace > &initializer)
constexpr bool operator==(const Tensor< rank_, dim, OtherNumber > &) const
constexpr Tensor< rank, dim, typename ProductType< Number, typename EnableIfScalar< OtherNumber >::type >::type > operator/(const Tensor< rank, dim, Number > &t, const OtherNumber &factor)
Definition tensor.h:2138
constexpr Tensor(const Tensor< 1, dim, Tensor< rank_ - 1, dim, OtherNumber > > &initializer)
constexpr const Number & operator[](const TableIndices< rank_ > &indices) const
constexpr Tensor< 0, dim, typename ProductType< Number, OtherNumber >::type > operator-(const Tensor< 0, dim, Number > &p, const Tensor< 0, dim, OtherNumber > &q)
Definition tensor.h:2064
constexpr Tensor< 0, dim, typename ProductType< Number, typename EnableIfScalar< OtherNumber >::type >::type > operator/(const Tensor< 0, dim, Number > &t, const OtherNumber &factor)
Definition tensor.h:2031
Number * begin_raw()
static constexpr unsigned int rank
Definition tensor.h:480
constexpr Tensor(const Tensor< rank_, dim, OtherNumber > &initializer)
std::conditional_t< rank_==1, Number, Tensor< rank_ - 1, dim, Number > > value_type
Definition tensor.h:505
numbers::NumberTraits< Number >::real_type norm() const
constexpr Tensor & operator-=(const Tensor< rank_, dim, OtherNumber > &)
constexpr void clear()
void unroll(const Iterator begin, const Iterator end) const
static constexpr unsigned int component_to_unrolled_index(const TableIndices< rank_ > &indices)
constexpr ProductType< Number, OtherNumber >::type operator*(const Tensor< 0, dim, Number > &src1, const Tensor< 0, dim, OtherNumber > &src2)
Definition tensor.h:2010
const Number * begin_raw() const
std::conditional_t< rank_==1, Number[(dim !=0) ? dim :1], typename Tensor< rank_ - 1, dim, Number >::array_type[(dim !=0) ? dim :1]> array_type
Definition tensor.h:521
constexpr bool operator!=(const Tensor< rank_, dim, OtherNumber > &) const
constexpr Tensor()
constexpr Tensor< 0, dim, typename ProductType< Number, OtherNumber >::type > schur_product(const Tensor< 0, dim, Number > &src1, const Tensor< 0, dim, OtherNumber > &src2)
Definition tensor.h:2196
constexpr value_type & operator[](const unsigned int i)
Number * end_raw()
friend class Tensor
Definition tensor.h:864
constexpr Tensor< rank, dim, typename ProductType< Number, OtherNumber >::type > operator+(const Tensor< rank, dim, Number > &p, const Tensor< rank, dim, OtherNumber > &q)
Definition tensor.h:2158
Number linfty_norm(const Tensor< 2, dim, Number > &t)
Definition tensor.h:3033
constexpr ProductType< Other, Number >::type operator*(const Other &object, const Tensor< 0, dim, Number > &t)
Definition tensor.h:1970
Number l1_norm(const Tensor< 2, dim, Number > &t)
Definition tensor.h:3007
static constexpr unsigned int dimension
Definition tensor.h:475
static constexpr TableIndices< rank_ > unrolled_to_component_indices(const unsigned int i)
constexpr Tensor & operator=(const Number &d) &&=delete
constexpr Tensor< rank, dim, typename ProductType< typename EnableIfScalar< Number >::type, OtherNumber >::type > operator*(const Number &factor, const Tensor< rank, dim, OtherNumber > &t)
Definition tensor.h:2115
static constexpr std::size_t memory_consumption()
constexpr Tensor & operator=(const Number &d) &
std::conditional_t< rank_==1, std::array< Number, dim >, std::array< Tensor< rank_ - 1, dim, Number >, dim > > values
Definition tensor.h:850
constexpr Tensor< 0, dim, typename ProductType< Number, OtherNumber >::type > operator+(const Tensor< 0, dim, Number > &p, const Tensor< 0, dim, OtherNumber > &q)
Definition tensor.h:2047
constexpr Tensor & operator+=(const Tensor< rank_, dim, OtherNumber > &)
const Number * end_raw() const
constexpr Number & operator[](const TableIndices< rank_ > &indices)
constexpr Tensor< rank, dim, typename ProductType< Number, OtherNumber >::type > schur_product(const Tensor< rank, dim, Number > &src1, const Tensor< rank, dim, OtherNumber > &src2)
Definition tensor.h:2225
constexpr numbers::NumberTraits< Number >::real_type norm_square() const
constexpr Tensor< rank, dim, typename ProductType< Number, OtherNumber >::type > operator-(const Tensor< rank, dim, Number > &p, const Tensor< rank, dim, OtherNumber > &q)
Definition tensor.h:2179
constexpr ProductType< Number, Other >::type operator*(const Tensor< 0, dim, Number > &t, const Other &object)
Definition tensor.h:1990
constexpr Tensor(const ArrayLike &initializer, std::index_sequence< Indices... >)
constexpr Tensor< rank, dim, typename ProductType< Number, typename EnableIfScalar< OtherNumber >::type >::type > operator*(const Tensor< rank, dim, Number > &t, const OtherNumber &factor)
Definition tensor.h:2089
void serialize(Archive &ar, const unsigned int version)
constexpr Tensor & operator*=(const OtherNumber &factor)
constexpr const value_type & operator[](const unsigned int i) const
constexpr Tensor(const array_type &initializer)
static constexpr unsigned int n_independent_components
Definition tensor.h:496
constexpr Tensor operator-() const
constexpr Tensor & operator=(const Tensor< rank_, dim, OtherNumber > &rhs)
#define DEAL_II_ALWAYS_INLINE
Definition config.h:166
#define DEAL_II_DEPRECATED
Definition config.h:294
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_CXX20_REQUIRES(condition)
Definition config.h:249
#define DEAL_II_CXX23_ASSUME(expr)
Definition config.h:266
#define DEAL_II_HOST_DEVICE
Definition config.h:171
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_HOST_DEVICE_ALWAYS_INLINE
Definition config.h:172
DerivativeForm< 1, spacedim, dim, Number > transpose(const DerivativeForm< 1, dim, spacedim, Number > &DF)
static ::ExceptionBase & ExcNotImplemented()
static ::ExceptionBase & ExcScalarAssignmentOnlyForZeroValue()
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
Expression fabs(const Expression &x)
constexpr char T
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
*  *  *  RotationFunction< dim, Number >::RotationFunction Number(dim)
*  *  *  *  std::vector< Number > ThermoPlasticMaterial< dim, ViscoplasticYieldLaw, Number >::get_state_parameters   const
constexpr internal::ReorderedIndexView< index, rank, T > reordered_index_view(T &t)
constexpr void contract(T1 &result, const T2 &left, const T3 &right)
constexpr T1 contract3(const T2 &left, const T3 &middle, const T4 &right)
T sum(const T &t, const MPI_Comm mpi_communicator)
constexpr bool values_are_not_equal(const Number1 &value_1, const Number2 &value_2)
Definition numbers.h:866
constexpr bool value_is_zero(const Number &value)
Definition numbers.h:874
constexpr bool values_are_equal(const Number1 &value_1, const Number2 &value_2)
Definition numbers.h:858
STL namespace.
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > abs(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:662
decltype(std::declval< T >() *std::declval< U >()) type
static real_type abs(const number &x)
Definition numbers.h:560
static constexpr real_type abs_square(const number &x)
Definition numbers.h:551
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 > outer_product(const SymmetricTensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, Number > &t2)
Tensor< 2, dim, Number > project_onto_orthogonal_tensors(const Tensor< 2, dim, Number > &A)
Definition tensor.cc:87
std::ostream & operator<<(std::ostream &out, const Tensor< rank_, dim, Number > &p)
Definition tensor.h:1920
constexpr Tensor< 0, dim, typename ProductType< Number, OtherNumber >::type > schur_product(const Tensor< 0, dim, Number > &src1, const Tensor< 0, dim, OtherNumber > &src2)
Definition tensor.h:2196
Number linfty_norm(const Tensor< 2, dim, Number > &t)
Definition tensor.h:3033
Number l1_norm(const Tensor< 2, dim, Number > &t)
Definition tensor.h:3007