deal.II version 9.7.0
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
tensor.h
Go to the documentation of this file.
1// ------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: 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// Part of the source code is dual licensed under Apache-2.0 WITH
9// LLVM-exception OR LGPL-2.1-or-later. Detailed license information
10// governing the source code and code contributions can be found in
11// LICENSE.md and CONTRIBUTING.md at the top level directory of deal.II.
12//
13// ------------------------------------------------------------------------
14
15#ifndef dealii_tensor_h
16#define dealii_tensor_h
17
18#include <deal.II/base/config.h>
19
21#include <deal.II/base/kokkos.h>
26
27#include <Kokkos_Array.hpp>
28
29#ifdef DEAL_II_WITH_ADOLC
30# include <adolc/adouble.h> // Taped double
31#endif
32
33#include <cmath>
34#include <complex>
35#include <ostream>
36#include <type_traits>
37
39
40// Forward declarations:
41#ifndef DOXYGEN
42template <typename ElementType, typename MemorySpace>
43class ArrayView;
44
45template <int dim, typename Number>
47class Point;
48
49template <int rank_, int dim, typename Number = double>
50class Tensor;
51template <typename Number>
52class Vector;
53template <typename number>
54class FullMatrix;
55namespace Differentiation
56{
57 namespace SD
58 {
59 class Expression;
60 }
61} // namespace Differentiation
62#endif
63
64
94template <int dim, typename Number>
95class Tensor<0, dim, Number>
96{
97public:
98 static_assert(dim >= 0,
99 "Tensors must have a dimension greater than or equal to one.");
100
109 static constexpr unsigned int dimension = dim;
110
114 static constexpr unsigned int rank = 0;
115
119 static constexpr unsigned int n_independent_components = 1;
120
130
135 using value_type = Number;
136
142 using array_type = Number;
143
149 constexpr DEAL_II_HOST_DEVICE
151
159 template <typename OtherNumber>
160 constexpr DEAL_II_HOST_DEVICE
162
168 template <typename OtherNumber>
169 constexpr DEAL_II_HOST_DEVICE
170 Tensor(const OtherNumber &initializer);
171
172#ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
176 constexpr DEAL_II_HOST_DEVICE
177 Tensor(const Tensor<0, dim, Number> &other);
178
182 constexpr DEAL_II_HOST_DEVICE
183 Tensor(Tensor<0, dim, Number> &&other) noexcept;
184#endif
185
195 constexpr DEAL_II_HOST_DEVICE
196 operator Number &();
197
206 constexpr DEAL_II_HOST_DEVICE operator const Number &() const;
207
215 template <typename OtherNumber>
216 constexpr DEAL_II_HOST_DEVICE Tensor &
218
219#if defined(__INTEL_COMPILER) || defined(DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG)
228 constexpr DEAL_II_HOST_DEVICE Tensor &
230#endif
231
232#ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
237 operator=(Tensor<0, dim, Number> &&other) noexcept;
238#endif
239
246 template <typename OtherNumber>
247 constexpr DEAL_II_HOST_DEVICE Tensor &
248 operator=(const OtherNumber &d) &;
249
255 template <typename OtherNumber>
256 constexpr DEAL_II_HOST_DEVICE Tensor &
257 operator=(const OtherNumber &d) && = delete;
258
262 template <typename OtherNumber>
263 constexpr bool
265
269 template <typename OtherNumber>
270 constexpr bool
272
278 template <typename OtherNumber>
279 constexpr DEAL_II_HOST_DEVICE Tensor &
281
287 template <typename OtherNumber>
288 constexpr DEAL_II_HOST_DEVICE Tensor &
290
296 template <typename OtherNumber>
297 constexpr DEAL_II_HOST_DEVICE Tensor &
298 operator*=(const OtherNumber &factor);
299
305 template <typename OtherNumber>
306 constexpr DEAL_II_HOST_DEVICE Tensor &
307 operator/=(const OtherNumber &factor);
308
315 operator-() const;
316
329 constexpr void
331
338 norm() const;
339
347 norm_square() const;
348
356 template <class Iterator>
357 void
358 unroll(const Iterator begin, const Iterator end) const;
359
365 template <class Archive>
366 void
367 serialize(Archive &ar, const unsigned int version);
368
373 using tensor_type = Number;
374
375private:
379 Number value;
380
381 // Allow an arbitrary Tensor to access the underlying values.
382 template <int, int, typename>
383 friend class Tensor;
384};
385
386
387
461template <int rank_, int dim, typename Number>
463{
464public:
465 static_assert(rank_ >= 1,
466 "Tensors must have a rank greater than or equal to one.");
467 static_assert(dim >= 0,
468 "Tensors must have a dimension greater than or equal to zero.");
477 static constexpr unsigned int dimension = dim;
478
482 static constexpr unsigned int rank = rank_;
483
498 static constexpr unsigned int n_independent_components =
499 Tensor<rank_ - 1, dim>::n_independent_components * dim;
500
507 std::conditional_t<rank_ == 1, Number, Tensor<rank_ - 1, dim, Number>>;
508
520 using array_type = std::conditional_t<
521 rank_ == 1,
522 Number[(dim != 0) ? dim : 1],
523 typename Tensor<rank_ - 1, dim, Number>::array_type[(dim != 0) ? dim : 1]>;
524
532
538 constexpr DEAL_II_HOST_DEVICE explicit Tensor(const array_type &initializer);
539
552 template <typename ElementType, typename MemorySpace>
553 constexpr DEAL_II_HOST_DEVICE explicit Tensor(
554 const ArrayView<ElementType, MemorySpace> &initializer);
555
563 template <typename OtherNumber>
564 constexpr DEAL_II_HOST_DEVICE
566
570 template <typename OtherNumber>
571 constexpr Tensor(
572 const Tensor<1, dim, Tensor<rank_ - 1, dim, OtherNumber>> &initializer);
573
577 template <typename OtherNumber>
578 constexpr
579 operator Tensor<1, dim, Tensor<rank_ - 1, dim, OtherNumber>>() const;
580
581#ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
585 constexpr Tensor(const Tensor<rank_, dim, Number> &);
586
590 constexpr Tensor(Tensor<rank_, dim, Number> &&) noexcept;
591#endif
592
599 operator[](const unsigned int i);
600
606 constexpr DEAL_II_HOST_DEVICE const value_type &
607 operator[](const unsigned int i) const;
608
612 constexpr const Number &
613 operator[](const TableIndices<rank_> &indices) const;
614
618 constexpr Number &
620
625 Number *
627
632 const Number *
633 begin_raw() const;
634
639 Number *
641
646 const Number *
647 end_raw() const;
648
656 template <typename OtherNumber>
657 constexpr DEAL_II_HOST_DEVICE Tensor &
659
666 constexpr DEAL_II_HOST_DEVICE Tensor &
667 operator=(const Number &d) &;
668
674 constexpr DEAL_II_HOST_DEVICE Tensor &
675 operator=(const Number &d) && = delete;
676
677#ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
683
689#endif
690
694 template <typename OtherNumber>
695 constexpr bool
697
701 template <typename OtherNumber>
702 constexpr bool
704
710 template <typename OtherNumber>
711 constexpr DEAL_II_HOST_DEVICE Tensor &
713
719 template <typename OtherNumber>
720 constexpr DEAL_II_HOST_DEVICE Tensor &
722
729 template <typename OtherNumber>
730 constexpr DEAL_II_HOST_DEVICE Tensor &
731 operator*=(const OtherNumber &factor);
732
738 template <typename OtherNumber>
739 constexpr DEAL_II_HOST_DEVICE Tensor &
740 operator/=(const OtherNumber &factor);
741
748 operator-() const;
749
762 constexpr void
764
774 norm() const;
775
782 constexpr DEAL_II_HOST_DEVICE
784 norm_square() const;
785
796 template <class Iterator>
797 void
798 unroll(const Iterator begin, const Iterator end) const;
799
804 static constexpr DEAL_II_HOST_DEVICE unsigned int
806
813 unrolled_to_component_indices(const unsigned int i);
814
819 static constexpr std::size_t
821
827 template <class Archive>
828 void
829 serialize(Archive &ar, const unsigned int version);
830
836
837private:
843#if DEAL_II_KOKKOS_VERSION_GTE(3, 7, 0)
844 std::conditional_t<rank_ == 1,
845 Kokkos::Array<Number, dim>,
846 Kokkos::Array<Tensor<rank_ - 1, dim, Number>, dim>>
847#else
848 std::conditional_t<rank_ == 1,
849 std::array<Number, dim>,
850 std::array<Tensor<rank_ - 1, dim, Number>, dim>>
851#endif
853
860 template <typename ArrayLike, std::size_t... Indices>
861 constexpr DEAL_II_HOST_DEVICE
862 Tensor(const ArrayLike &initializer, std::index_sequence<Indices...>);
863
864 // Allow an arbitrary Tensor to access the underlying values.
865 template <int, int, typename>
866 friend class Tensor;
867
868 // Point is allowed access to the coordinates. This is supposed to improve
869 // speed.
870 friend class Point<dim, Number>;
871};
872
873
874#ifndef DOXYGEN
875namespace internal
876{
877 // Workaround: The following 4 overloads are necessary to be able to
878 // compile the library with Apple Clang 8 and older. We should remove
879 // these overloads again when we bump the minimal required version to
880 // something later than clang-3.6 / Apple Clang 6.3.
881 template <int rank, int dim, typename T, typename U>
882 struct ProductTypeImpl<Tensor<rank, dim, T>, std::complex<U>>
883 {
884 using type =
886 };
887
888 template <int rank, int dim, typename T, typename U>
889 struct ProductTypeImpl<Tensor<rank, dim, std::complex<T>>, std::complex<U>>
890 {
891 using type =
892 Tensor<rank, dim, std::complex<typename ProductType<T, U>::type>>;
893 };
894
895 template <typename T, int rank, int dim, typename U>
896 struct ProductTypeImpl<std::complex<T>, Tensor<rank, dim, U>>
897 {
898 using type =
899 Tensor<rank, dim, std::complex<typename ProductType<T, U>::type>>;
900 };
901
902 template <int rank, int dim, typename T, typename U>
903 struct ProductTypeImpl<std::complex<T>, Tensor<rank, dim, std::complex<U>>>
904 {
905 using type =
906 Tensor<rank, dim, std::complex<typename ProductType<T, U>::type>>;
907 };
908 // end workaround
909
914 template <int rank, int dim, typename T>
915 struct NumberType<Tensor<rank, dim, T>>
916 {
917 static constexpr DEAL_II_HOST_DEVICE_ALWAYS_INLINE const
918 Tensor<rank, dim, T> &
919 value(const Tensor<rank, dim, T> &t)
920 {
921 return t;
922 }
923
924 static constexpr DEAL_II_HOST_DEVICE_ALWAYS_INLINE Tensor<rank, dim, T>
925 value(const T &t)
926 {
927 Tensor<rank, dim, T> tmp;
928 tmp = t;
929 return tmp;
930 }
931 };
932} // namespace internal
933
934
935/*---------------------- Inline functions: Tensor<0,dim> ---------------------*/
936
937
938template <int dim, typename Number>
941 // Some auto-differentiable numbers need explicit
942 // zero initialization such as adtl::adouble.
943 : Tensor{0.0}
944{}
945
946
947
948template <int dim, typename Number>
949template <typename OtherNumber>
951Tensor<0, dim, Number>::Tensor(const OtherNumber &initializer)
952 : value(internal::NumberType<Number>::value(initializer))
953{}
954
955
956
957template <int dim, typename Number>
958template <typename OtherNumber>
961 : Tensor{p.value}
962{}
963
964
965# ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
966template <int dim, typename Number>
969 : value{other.value}
970{}
971
972
973
974template <int dim, typename Number>
977 : value{std::move(other.value)}
978{}
979# endif
980
981
982
983template <int dim, typename Number>
986{
987 Assert(dim != 0,
988 ExcMessage("Cannot access an object of type Tensor<0,0,Number>"));
989 return value;
990}
991
992
993template <int dim, typename Number>
994constexpr inline DEAL_II_ALWAYS_INLINE
996{
997 Assert(dim != 0,
998 ExcMessage("Cannot access an object of type Tensor<0,0,Number>"));
999 return value;
1000}
1001
1002
1003
1004template <int dim, typename Number>
1005template <typename OtherNumber>
1008{
1010 return *this;
1011}
1012
1013
1014# if defined(__INTEL_COMPILER) || defined(DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG)
1015template <int dim, typename Number>
1018{
1019 value = p.value;
1020 return *this;
1021}
1022# endif
1023
1024# ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
1025template <int dim, typename Number>
1028{
1029 value = std::move(other.value);
1030 return *this;
1031}
1032# endif
1033
1034
1035
1036template <int dim, typename Number>
1037template <typename OtherNumber>
1039Tensor<0, dim, Number>::operator=(const OtherNumber &d) &
1040{
1042 return *this;
1043}
1044
1045
1046template <int dim, typename Number>
1047template <typename OtherNumber>
1048constexpr inline bool
1050{
1051# ifdef DEAL_II_ADOLC_WITH_ADVANCED_BRANCHING
1052 Assert(!(std::is_same_v<Number, adouble> ||
1053 std::is_same_v<OtherNumber, adouble>),
1054 ExcMessage(
1055 "The Tensor equality operator for ADOL-C taped numbers has not yet "
1056 "been extended to support advanced branching."));
1057# endif
1058
1059 return numbers::values_are_equal(value, p.value);
1060}
1061
1062
1063template <int dim, typename Number>
1064template <typename OtherNumber>
1065constexpr bool
1067{
1068 return !((*this) == p);
1069}
1070
1071
1072template <int dim, typename Number>
1073template <typename OtherNumber>
1076{
1077 value += p.value;
1078 return *this;
1079}
1080
1081
1082template <int dim, typename Number>
1083template <typename OtherNumber>
1086{
1087 value -= p.value;
1088 return *this;
1089}
1090
1091
1092
1093namespace internal
1094{
1095 namespace ComplexWorkaround
1096 {
1097 template <typename Number, typename OtherNumber>
1099 multiply_assign_scalar(Number &val, const OtherNumber &s)
1100 {
1101 val *= s;
1102 }
1103
1104 template <typename Number, typename OtherNumber>
1106 multiply_assign_scalar(std::complex<Number> &val, const OtherNumber &s)
1107 {
1108# if DEAL_II_KOKKOS_VERSION_GTE(3, 6, 0)
1109 KOKKOS_IF_ON_HOST((val *= s;))
1110 KOKKOS_IF_ON_DEVICE(({
1111 (void)val;
1112 (void)s;
1113 Kokkos::abort(
1114 "This function is not implemented for std::complex<Number>!\n");
1115 }))
1116# else
1117# ifdef KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST
1118 val *= s;
1119# else
1120 (void)val;
1121 (void)s;
1122 Kokkos::abort(
1123 "This function is not implemented for std::complex<Number>!\n");
1124# endif
1125# endif
1126 }
1127 } // namespace ComplexWorkaround
1128} // namespace internal
1129
1130
1131template <int dim, typename Number>
1132template <typename OtherNumber>
1134Tensor<0, dim, Number>::operator*=(const OtherNumber &s)
1135{
1136 internal::ComplexWorkaround::multiply_assign_scalar(value, s);
1137 return *this;
1138}
1139
1140
1141
1142template <int dim, typename Number>
1143template <typename OtherNumber>
1145Tensor<0, dim, Number>::operator/=(const OtherNumber &s)
1146{
1147 value /= s;
1148 return *this;
1149}
1150
1151
1152template <int dim, typename Number>
1155{
1156 return -value;
1157}
1158
1159
1160template <int dim, typename Number>
1163{
1164 Assert(dim != 0,
1165 ExcMessage("Cannot access an object of type Tensor<0,0,Number>"));
1167}
1168
1169
1170template <int dim, typename Number>
1174{
1175 Assert(dim != 0,
1176 ExcMessage("Cannot access an object of type Tensor<0,0,Number>"));
1178}
1179
1180
1181
1182template <int dim, typename Number>
1183constexpr inline void
1185{
1186 // Some auto-differentiable numbers need explicit
1187 // zero initialization.
1189}
1190
1191
1192
1193template <int dim, typename Number>
1194template <class Iterator>
1195inline void
1196Tensor<0, dim, Number>::unroll(const Iterator begin, const Iterator end) const
1197{
1198 AssertDimension(std::distance(begin, end), n_independent_components);
1199 Assert(dim != 0,
1200 ExcMessage("Cannot unroll an object of type Tensor<0,0,Number>"));
1201 Assert(std::distance(begin, end) >= 1,
1202 ExcMessage("The provided iterator range must contain at least one "
1203 "element."));
1204 *begin = value;
1205}
1206
1207
1208
1209template <int dim, typename Number>
1210template <class Archive>
1211inline void
1212Tensor<0, dim, Number>::serialize(Archive &ar, const unsigned int)
1213{
1214 ar &value;
1215}
1216
1217
1218template <int dim, typename Number>
1220
1221
1222/*-------------------- Inline functions: Tensor<rank,dim> --------------------*/
1223
1224template <int rank_, int dim, typename Number>
1225template <typename ArrayLike, std::size_t... indices>
1227Tensor<rank_, dim, Number>::Tensor(const ArrayLike &initializer,
1228 std::index_sequence<indices...>)
1229 // Extract from the 'initializer' a sequence of elements via template
1230 // pack evaluation. This could be as easy as
1231 // values{{ (initializer[indices])... }}
1232 // but of course in practice it is not. The challenge is that if rank>1,
1233 // we want to pass the elements initializer[indices] down to the next
1234 // lower rank tensor for evaluation unchanged. But at the rank==1 level,
1235 // we need to convert to the scalar type 'Number'. This would all be
1236 // relatively straightforward if we could rely on automatic type
1237 // conversion, but for some autodifferentiation types, the conversion
1238 // from the AD to double (i.e., the extraction of a scalar value) is
1239 // not implicit, and we need to call internal::NumberType<Number>::value() --
1240 // but as mentioned, we can only do that for rank==1.
1241 //
1242 // We can achieve all of this by dispatching to a lambda function within
1243 // which we can use a 'if constexpr'.
1244 : values{{([&initializer]() -> value_type {
1245 if constexpr (rank_ == 1)
1246 return internal::NumberType<Number>::value(initializer[indices]);
1247 else
1248 return value_type(initializer[indices]);
1249 }())...}}
1250{
1251 static_assert(sizeof...(indices) == dim,
1252 "dim should match the number of indices");
1253}
1254
1255
1256# if defined(DEAL_II_HAVE_CXX20) && !defined(__NVCC__)
1257
1258template <int rank_, int dim, typename Number>
1261 : values(
1262 // In order to initialize the Kokkos::Array<Number,dim>, we would need a
1263 // brace-enclosed list of length 'dim'. There is no way in C++ to create
1264 // such a list in-place, but we can come up with a lambda function that
1265 // expands such a list via template-pack expansion, and then uses this
1266 // list to initialize a Kokkos::Array which it then returns.
1267 //
1268 // The trick to come up with such a lambda function is to have a function
1269 // that takes an argument that depends on a template-pack of integers.
1270 // We will call the function with an integer list of length 'dim', and
1271 // in the function itself expand that pack in a way that it serves as
1272 // a brace-enclosed list of initializers for a Kokkos::Array.
1273 //
1274 // Of course, we do not want to initialize the array with the integers,
1275 // but with zeros. (Or, more correctly, a zero of the element type.)
1276 // The canonical way to do this would be using the comma operator:
1277 // (sequence_element, 0.0)
1278 // returns zero, and
1279 // (sequence, 0.0)...
1280 // returns a list of zeros of the right length. Unfortunately, some
1281 // compilers then warn that the left side of the comma expression has
1282 // no effect -- well, bummer, that was of course exactly the idea.
1283 // We could work around this by using
1284 // (sequence_element * 0.0)
1285 // instead, assuming that the compiler will optimize (known) integer
1286 // times zero to zero, and similarly for (known) integer times times
1287 // default-initialized tensor.
1288 //
1289 // But, instead of relying on compiler optimizations, a better way is
1290 // to simply have another (nested) lambda function that takes the
1291 // integer sequence element as an argument and ignores it, just
1292 // returning a zero instead.
1293 []<std::size_t... I>(
1294 const std::index_sequence<I...> &) constexpr -> decltype(values) {
1295 if constexpr (dim == 0)
1296 {
1297 return {};
1298 }
1299 else if constexpr (rank_ == 1)
1300 {
1301 auto get_zero_and_ignore_argument = [](int) {
1303 };
1304 return {{(get_zero_and_ignore_argument(I))...}};
1305 }
1306 else
1307 {
1308 auto get_zero_and_ignore_argument = [](int) {
1309 return Tensor<rank_ - 1, dim, Number>();
1310 };
1311 return {{(get_zero_and_ignore_argument(I))...}};
1312 }
1313 }(std::make_index_sequence<dim>()))
1314{}
1315
1316# else
1317
1318// The C++17 case works in essence the same, except that we can't use a
1319// lambda function with explicit template parameters, i.e., we can't do
1320// []<std::size_t... I>(const std::index_sequence<I...> &)
1321// as above because that's a C++20 feature. Lambda functions in C++17 can
1322// have template packs as arguments, but we need the ability to *name*
1323// that template pack (the 'I' above) and that's not possible in C++17.
1324//
1325// We work around this by moving the lambda function to a global function
1326// and using the traditional template syntax on it.
1327namespace internal
1328{
1329 namespace TensorInitialization
1330 {
1331 template <int rank, int dim, typename Number, std::size_t... I>
1332# if DEAL_II_KOKKOS_VERSION_GTE(3, 7, 0)
1333 constexpr Kokkos::Array<typename Tensor<rank, dim, Number>::value_type, dim>
1334# else
1335 constexpr std::array<typename Tensor<rank, dim, Number>::value_type, dim>
1336# endif
1337 make_zero_array(const std::index_sequence<I...> &)
1338 {
1339 static_assert(sizeof...(I) == dim, "This is bad.");
1340
1341 // First peel off the case dim==0. If we don't, some compilers
1342 // will warn below that we define these lambda functions but
1343 // never use them (because the expanded list has zero elements,
1344 // and the get_zero_and_ignore_argument() function is not used...)
1345 if constexpr (dim == 0)
1346 {
1347 return {};
1348 }
1349 else if constexpr (rank == 1)
1350 {
1351 auto get_zero_and_ignore_argument = [](int) {
1353 };
1354 return {{(get_zero_and_ignore_argument(I))...}};
1355 }
1356 else
1357 {
1358 auto get_zero_and_ignore_argument = [](int) {
1359 return Tensor<rank - 1, dim, Number>();
1360 };
1361 return {{(get_zero_and_ignore_argument(I))...}};
1362 }
1363 }
1364 } // namespace TensorInitialization
1365} // namespace internal
1366
1367
1368template <int rank_, int dim, typename Number>
1371 : values(internal::TensorInitialization::make_zero_array<rank_, dim, Number>(
1372 std::make_index_sequence<dim>()))
1373{}
1374
1375
1376# endif
1377
1378
1379template <int rank_, int dim, typename Number>
1381Tensor<rank_, dim, Number>::Tensor(const array_type &initializer)
1382 : Tensor(initializer, std::make_index_sequence<dim>{})
1383{}
1384
1385
1386
1387template <int rank_, int dim, typename Number>
1388template <typename ElementType, typename MemorySpace>
1391 const ArrayView<ElementType, MemorySpace> &initializer)
1392{
1393 // make nvcc happy
1394 const int my_n_independent_components = n_independent_components;
1395 AssertDimension(initializer.size(), my_n_independent_components);
1396
1397 for (unsigned int i = 0; i < my_n_independent_components; ++i)
1398 (*this)[unrolled_to_component_indices(i)] = initializer[i];
1399}
1400
1401
1402
1403template <int rank_, int dim, typename Number>
1404template <typename OtherNumber>
1407 const Tensor<rank_, dim, OtherNumber> &initializer)
1408 : Tensor(initializer, std::make_index_sequence<dim>{})
1409{}
1410
1411
1412
1413template <int rank_, int dim, typename Number>
1414template <typename OtherNumber>
1415constexpr DEAL_II_ALWAYS_INLINE
1417 const Tensor<1, dim, Tensor<rank_ - 1, dim, OtherNumber>> &initializer)
1418 : Tensor(initializer, std::make_index_sequence<dim>{})
1419{}
1420
1421
1422
1423template <int rank_, int dim, typename Number>
1424template <typename OtherNumber>
1426operator Tensor<1, dim, Tensor<rank_ - 1, dim, OtherNumber>>() const
1427{
1428 Tensor<1, dim, Tensor<rank_ - 1, dim, OtherNumber>> x;
1429 std::copy(values.data(), values.data() + values.size(), x.values.data());
1430 return x;
1431}
1432
1433
1434# ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
1435template <int rank_, int dim, typename Number>
1436constexpr DEAL_II_ALWAYS_INLINE
1438 : values(other.values)
1439{}
1440
1441
1442
1443template <int rank_, int dim, typename Number>
1444constexpr DEAL_II_ALWAYS_INLINE
1446 : values(std::move(other.values))
1447{}
1448# endif
1449
1450
1451
1452template <int rank_, int dim, typename Number>
1455 Tensor<rank_, dim, Number>::operator[](const unsigned int i)
1456{
1457 Assert(dim != 0,
1458 ExcMessage("Cannot access an object of type Tensor<rank_,0,Number>"));
1459 AssertIndexRange(i, dim);
1460 DEAL_II_CXX23_ASSUME(i < dim);
1461
1462 return values[i];
1463}
1464
1465
1466template <int rank_, int dim, typename Number>
1467constexpr DEAL_II_ALWAYS_INLINE
1469 Tensor<rank_, dim, Number>::operator[](const unsigned int i) const
1470{
1471 Assert(dim != 0,
1472 ExcMessage("Cannot access an object of type Tensor<rank_,0,Number>"));
1473 AssertIndexRange(i, dim);
1474 DEAL_II_CXX23_ASSUME(i < dim);
1475
1476 return values[i];
1477}
1478
1479
1480template <int rank_, int dim, typename Number>
1481constexpr inline DEAL_II_ALWAYS_INLINE const Number &
1483{
1484 Assert(dim != 0,
1485 ExcMessage("Cannot access an object of type Tensor<rank_,0,Number>"));
1486
1487 return TensorAccessors::extract<rank_>(*this, indices);
1488}
1489
1490
1491
1492template <int rank_, int dim, typename Number>
1493constexpr inline DEAL_II_ALWAYS_INLINE Number &
1495{
1496 Assert(dim != 0,
1497 ExcMessage("Cannot access an object of type Tensor<rank_,0,Number>"));
1498
1499 return TensorAccessors::extract<rank_>(*this, indices);
1500}
1501
1502
1503
1504template <int rank_, int dim, typename Number>
1505inline Number *
1507{
1508 static_assert(rank_ == 1,
1509 "This function is only available for rank-1 tensors "
1510 "because higher-rank tensors may not store their elements "
1511 "in a contiguous array.");
1512
1513 return std::addressof(
1514 this->operator[](this->unrolled_to_component_indices(0)));
1515}
1516
1517
1518
1519template <int rank_, int dim, typename Number>
1520inline const Number *
1522{
1523 static_assert(rank_ == 1,
1524 "This function is only available for rank-1 tensors "
1525 "because higher-rank tensors may not store their elements "
1526 "in a contiguous array.");
1527
1528 return std::addressof(
1529 this->operator[](this->unrolled_to_component_indices(0)));
1530}
1531
1532
1533
1534template <int rank_, int dim, typename Number>
1535inline Number *
1537{
1538 static_assert(rank_ == 1,
1539 "This function is only available for rank-1 tensors "
1540 "because higher-rank tensors may not store their elements "
1541 "in a contiguous array.");
1542
1543 return begin_raw() + n_independent_components;
1544}
1545
1546
1547
1548template <int rank_, int dim, typename Number>
1549inline const Number *
1551{
1552 static_assert(rank_ == 1,
1553 "This function is only available for rank-1 tensors "
1554 "because higher-rank tensors may not store their elements "
1555 "in a contiguous array.");
1556
1557 return begin_raw() + n_independent_components;
1558}
1559
1560
1561
1562template <int rank_, int dim, typename Number>
1563template <typename OtherNumber>
1566{
1567 // The following loop could be written more concisely using std::copy, but
1568 // that function is only constexpr from C++20 on.
1569 for (unsigned int i = 0; i < dim; ++i)
1570 values[i] = t.values[i];
1571 return *this;
1572}
1573
1574
1575
1576template <int rank_, int dim, typename Number>
1579 Tensor<rank_, dim, Number>::operator=(const Number &d) &
1580{
1582
1583 for (unsigned int i = 0; i < dim; ++i)
1584 values[i] = internal::NumberType<Number>::value(0.0);
1585 return *this;
1586}
1587
1588
1589# ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
1590template <int rank_, int dim, typename Number>
1593{
1594 for (unsigned int i = 0; i < dim; ++i)
1595 values[i] = other.values[i];
1596 return *this;
1597}
1598
1599
1600
1601template <int rank_, int dim, typename Number>
1604 Tensor<rank_, dim, Number> &&other) noexcept
1605{
1606 for (unsigned int i = 0; i < dim; ++i)
1607 values[i] = other.values[i];
1608 return *this;
1609}
1610# endif
1611
1612
1613template <int rank_, int dim, typename Number>
1614template <typename OtherNumber>
1615constexpr inline bool
1617 const Tensor<rank_, dim, OtherNumber> &p) const
1618{
1619# ifdef DEAL_II_ADOLC_WITH_ADVANCED_BRANCHING
1620 Assert(!(std::is_same_v<Number, adouble> ||
1621 std::is_same_v<OtherNumber, adouble>),
1622 ExcMessage(
1623 "The Tensor equality operator for ADOL-C taped numbers has not yet "
1624 "been extended to support advanced branching."));
1625# endif
1626
1627 for (unsigned int i = 0; i < dim; ++i)
1628 if (numbers::values_are_not_equal(values[i], p.values[i]))
1629 return false;
1630 return true;
1631}
1632
1633
1634// At some places in the library, we have Point<0> for formal reasons
1635// (e.g., we sometimes have Quadrature<dim-1> for faces, so we have
1636// Quadrature<0> for dim=1, and then we have Point<0>). To avoid warnings
1637// in the above function that the loop end check always fails, we
1638// implement this function here
1639template <>
1640template <>
1641constexpr inline bool
1643{
1644 return true;
1645}
1646
1647
1648template <int rank_, int dim, typename Number>
1649template <typename OtherNumber>
1650constexpr bool
1652 const Tensor<rank_, dim, OtherNumber> &p) const
1653{
1654 return !((*this) == p);
1655}
1656
1657
1658template <int rank_, int dim, typename Number>
1659template <typename OtherNumber>
1660constexpr inline DEAL_II_ALWAYS_INLINE
1664{
1665 for (unsigned int i = 0; i < dim; ++i)
1666 values[i] += p.values[i];
1667 return *this;
1668}
1669
1670
1671template <int rank_, int dim, typename Number>
1672template <typename OtherNumber>
1673constexpr inline DEAL_II_ALWAYS_INLINE
1677{
1678 for (unsigned int i = 0; i < dim; ++i)
1679 values[i] -= p.values[i];
1680 return *this;
1681}
1682
1683
1684template <int rank_, int dim, typename Number>
1685template <typename OtherNumber>
1686constexpr inline DEAL_II_ALWAYS_INLINE
1688 Tensor<rank_, dim, Number>::operator*=(const OtherNumber &s)
1689{
1690 for (unsigned int i = 0; i < dim; ++i)
1691 values[i] *= s;
1692 return *this;
1693}
1694
1695
1696
1697template <int rank_, int dim, typename Number>
1698template <typename OtherNumber>
1699constexpr inline DEAL_II_ALWAYS_INLINE
1701 Tensor<rank_, dim, Number>::operator/=(const OtherNumber &s)
1702{
1703 if constexpr (std::is_integral_v<
1705 std::is_same_v<Number, Differentiation::SD::Expression>)
1706 {
1707 // recurse over the base objects
1708 for (unsigned int d = 0; d < dim; ++d)
1709 values[d] /= s;
1710 }
1711 else
1712 {
1713 // If we can, avoid division by multiplying by the inverse of the given
1714 // factor:
1715 const Number inverse_factor = Number(1.) / s;
1716 for (unsigned int d = 0; d < dim; ++d)
1717 values[d] *= inverse_factor;
1718 }
1719
1720 return *this;
1721}
1722
1723
1724template <int rank_, int dim, typename Number>
1725constexpr inline DEAL_II_ALWAYS_INLINE
1728{
1730
1731 for (unsigned int i = 0; i < dim; ++i)
1732 tmp.values[i] = -values[i];
1733
1734 return tmp;
1735}
1736
1737
1738template <int rank_, int dim, typename Number>
1741{
1742 // Handle cases of a tensor consisting of just one number more
1743 // efficiently:
1744 if constexpr ((rank_ == 1) && (dim == 1) && std::is_arithmetic_v<Number>)
1745 {
1746 return std::abs(values[0]);
1747 }
1748 else if constexpr ((rank_ == 2) && (dim == 1) && std::is_arithmetic_v<Number>)
1749 {
1750 return std::abs(values[0][0]);
1751 }
1752 else
1753 {
1754 // Otherwise fall back to the naive algorithm of taking the square root of
1755 // the sum of squares.
1756
1757 // Make things work with AD types by letting the compiler look up
1758 // the symbol sqrt in namespace std and in the type-associated
1759 // namespaces
1760 using std::sqrt;
1761 return sqrt(norm_square());
1762 }
1763}
1764
1765
1766template <int rank_, int dim, typename Number>
1770{
1771 if constexpr (dim == 0)
1772 return internal::NumberType<
1774 else if constexpr (rank_ == 1)
1775 {
1776 // For rank-1 tensors, the square of the norm is simply the sum of
1777 // squares of the elements:
1780 for (unsigned int i = 1; i < dim; ++i)
1782
1783 return s;
1784 }
1785 else
1786 {
1787 // For higher-rank tensors, the square of the norm is the sum
1788 // of squares of sub-tensors
1790 values[0].norm_square();
1791 for (unsigned int i = 1; i < dim; ++i)
1792 s += values[i].norm_square();
1793
1794 return s;
1795 }
1796}
1797
1798
1799
1800template <int rank_, int dim, typename Number>
1801template <class Iterator>
1802inline void
1803Tensor<rank_, dim, Number>::unroll(const Iterator begin,
1804 const Iterator end) const
1805{
1806 if constexpr (rank_ > 1)
1807 {
1808 // For higher-rank tensors, we recurse to the sub-tensors:
1809 Iterator next = begin;
1810 for (unsigned int i = 0; i < dim; ++i)
1811 {
1812 values[i].unroll(next, end);
1813 std::advance(
1815 }
1816 }
1817 else
1818 {
1819 // For rank-1 tensors, we can simply copy the current elements from
1820 // our linear array into the output range:
1821 Assert(std::distance(begin, end) >= dim,
1822 ExcMessage(
1823 "The provided iterator range must contain at least 'dim' "
1824 "elements."));
1825 std::copy(values.data(), values.data() + values.size(), begin);
1826 }
1827}
1828
1829
1830
1831template <int rank_, int dim, typename Number>
1832constexpr inline unsigned int
1834 const TableIndices<rank_> &indices)
1835{
1836 unsigned int index = 0;
1837 for (int r = 0; r < rank_; ++r)
1838 index = index * dim + indices[r];
1839
1840 return index;
1841}
1842
1843
1844
1845template <int rank_, int dim, typename Number>
1846constexpr inline TableIndices<rank_>
1848{
1849 // Work-around nvcc warning
1850 unsigned int dummy = n_independent_components;
1851 AssertIndexRange(i, dummy);
1852
1853 if constexpr (dim == 0)
1854 {
1855 Assert(false,
1856 ExcMessage(
1857 "A tensor with dimension 0 does not store any elements. "
1858 "There is no indexing that can address its elements."));
1859 return {};
1860 }
1861 else
1862 {
1863 TableIndices<rank_> indices;
1864
1865 unsigned int remainder = i;
1866 for (int r = rank_ - 1; r >= 0; --r)
1867 {
1868 indices[r] = remainder % dim;
1869 remainder = remainder / dim;
1870 }
1871 Assert(remainder == 0, ExcInternalError());
1872
1873 return indices;
1874 }
1875}
1876
1877
1878template <int rank_, int dim, typename Number>
1879constexpr inline void
1881{
1882 for (unsigned int i = 0; i < dim; ++i)
1883 values[i] = internal::NumberType<Number>::value(0.0);
1884}
1885
1886
1887template <int rank_, int dim, typename Number>
1888constexpr std::size_t
1890{
1891 return sizeof(Tensor<rank_, dim, Number>);
1892}
1893
1894
1895template <int rank_, int dim, typename Number>
1896template <class Archive>
1897inline void
1898Tensor<rank_, dim, Number>::serialize(Archive &ar, const unsigned int)
1899{
1900 for (int i = 0; i < dim; ++i)
1901 {
1902 ar &values[i];
1903 }
1904}
1905
1906
1907template <int rank_, int dim, typename Number>
1909
1910#endif // DOXYGEN
1911
1912/* ----------------- Non-member functions operating on tensors. ------------ */
1913
1918
1926template <int rank_, int dim, typename Number>
1927inline std::ostream &
1928operator<<(std::ostream &out, const Tensor<rank_, dim, Number> &p)
1929{
1930 for (unsigned int i = 0; i < dim; ++i)
1931 {
1932 out << p[i];
1933 if (i != dim - 1)
1934 for (unsigned int j = 0; j < rank_; ++j)
1935 out << ' ';
1936 }
1937
1938 return out;
1939}
1940
1941
1948template <int dim, typename Number>
1949inline std::ostream &
1950operator<<(std::ostream &out, const Tensor<0, dim, Number> &p)
1951{
1952 out << static_cast<const Number &>(p);
1953 return out;
1954}
1955
1956
1964
1975template <int dim, typename Number, typename Other>
1978 operator*(const Other &object, const Tensor<0, dim, Number> &t)
1979{
1980 return object * static_cast<const Number &>(t);
1981}
1982
1983
1984
1995template <int dim, typename Number, typename Other>
1998 operator*(const Tensor<0, dim, Number> &t, const Other &object)
1999{
2000 return static_cast<const Number &>(t) * object;
2001}
2002
2003
2015template <int dim, typename Number, typename OtherNumber>
2019 const Tensor<0, dim, OtherNumber> &src2)
2020{
2021 return static_cast<const Number &>(src1) *
2022 static_cast<const OtherNumber &>(src2);
2023}
2024
2025
2033template <int dim, typename Number, typename OtherNumber>
2035 Tensor<0,
2036 dim,
2037 typename ProductType<Number,
2038 typename EnableIfScalar<OtherNumber>::type>::type>
2039 operator/(const Tensor<0, dim, Number> &t, const OtherNumber &factor)
2040{
2041 return static_cast<const Number &>(t) / factor;
2042}
2043
2044
2052template <int dim, typename Number, typename OtherNumber>
2057{
2058 return static_cast<const Number &>(p) + static_cast<const OtherNumber &>(q);
2059}
2060
2061
2069template <int dim, typename Number, typename OtherNumber>
2074{
2075 return static_cast<const Number &>(p) - static_cast<const OtherNumber &>(q);
2076}
2077
2078
2091template <int rank, int dim, typename Number, typename OtherNumber>
2093 Tensor<rank,
2094 dim,
2095 typename ProductType<Number,
2096 typename EnableIfScalar<OtherNumber>::type>::type>
2097 operator*(const Tensor<rank, dim, Number> &t, const OtherNumber &factor)
2098{
2100 tt *= factor;
2101 return tt;
2102}
2103
2104
2117template <int rank, int dim, typename Number, typename OtherNumber>
2119 Tensor<rank,
2120 dim,
2122 OtherNumber>::type>
2123 operator*(const Number &factor, const Tensor<rank, dim, OtherNumber> &t)
2124{
2125 // simply forward to the operator above
2126 return t * factor;
2127}
2128
2129
2130
2140template <int rank, int dim, typename Number, typename OtherNumber>
2142 Tensor<rank,
2143 dim,
2144 typename ProductType<Number,
2145 typename EnableIfScalar<OtherNumber>::type>::type>
2146 operator/(const Tensor<rank, dim, Number> &t, const OtherNumber &factor)
2147{
2149 tt /= factor;
2150 return tt;
2151}
2152
2153
2163template <int rank, int dim, typename Number, typename OtherNumber>
2173
2174
2184template <int rank, int dim, typename Number, typename OtherNumber>
2194
2201template <int dim, typename Number, typename OtherNumber>
2202inline constexpr DEAL_II_ALWAYS_INLINE
2205 const Tensor<0, dim, OtherNumber> &src2)
2206{
2208
2209 tmp *= src2;
2210
2211 return tmp;
2212}
2213
2230template <int rank, int dim, typename Number, typename OtherNumber>
2231inline constexpr DEAL_II_ALWAYS_INLINE
2235{
2237
2238 for (unsigned int i = 0; i < dim; ++i)
2241
2242 return tmp;
2243}
2244
2252
2289template <int rank_1,
2290 int rank_2,
2291 int dim,
2292 typename Number,
2293 typename OtherNumber,
2294 typename = std::enable_if_t<rank_1 >= 1 && rank_2 >= 1>>
2295constexpr inline DEAL_II_ALWAYS_INLINE
2296 typename Tensor<rank_1 + rank_2 - 2,
2297 dim,
2298 typename ProductType<Number, OtherNumber>::type>::tensor_type
2301{
2302 // Treat some common cases separately. Specifically, these are the dot
2303 // product between two rank-1 tensors, and the product between a
2304 // rank-2 tensor and a rank-1 tensor. Both of these lead to a linear
2305 // loop over adjacent memory and can be dealt with efficiently; in the
2306 // latter case (rank-2 times rank-1), we implement things by deferring
2307 // to rank-1 times rank-1 dot products.
2308 if constexpr ((rank_1 == 1) && (rank_2 == 1))
2309 {
2310 // This is a dot product between two rank-1 tensors. Write it out as
2311 // a linear loop:
2312 static_assert(dim > 0, "Tensors cannot have dimension zero.");
2313 typename ProductType<Number, OtherNumber>::type sum = src1[0] * src2[0];
2314 for (unsigned int i = 1; i < dim; ++i)
2315 sum += src1[i] * src2[i];
2316
2317 return sum;
2318 }
2319 else if constexpr ((rank_1 == 2) && (rank_2 == 1))
2320 {
2321 // This is a product between a rank-2 and a rank-1 tensor. This
2322 // corresponds to taking dot products between the rows of the former
2323 // and the latter.
2324 typename Tensor<
2325 rank_1 + rank_2 - 2,
2326 dim,
2328 for (unsigned int i = 0; i < dim; ++i)
2329 result[i] += src1[i] * src2;
2330
2331 return result;
2332 }
2333 else
2334 {
2335 // Treat all of the other cases using the more general contraction
2336 // machinery.
2337 typename Tensor<
2338 rank_1 + rank_2 - 2,
2339 dim,
2341
2342 TensorAccessors::internal::
2343 ReorderedIndexView<0, rank_2, const Tensor<rank_2, dim, OtherNumber>>
2346 src1,
2347 reordered);
2348
2349 return result;
2350 }
2351}
2352
2353
2382template <int index_1,
2383 int index_2,
2384 int rank_1,
2385 int rank_2,
2386 int dim,
2387 typename Number,
2388 typename OtherNumber>
2389constexpr inline DEAL_II_ALWAYS_INLINE
2390 typename Tensor<rank_1 + rank_2 - 2,
2391 dim,
2392 typename ProductType<Number, OtherNumber>::type>::tensor_type
2395{
2396 Assert(0 <= index_1 && index_1 < rank_1,
2397 ExcMessage(
2398 "The specified index_1 must lie within the range [0,rank_1)"));
2399 Assert(0 <= index_2 && index_2 < rank_2,
2400 ExcMessage(
2401 "The specified index_2 must lie within the range [0,rank_2)"));
2402
2403 using namespace TensorAccessors;
2404 using namespace TensorAccessors::internal;
2405
2406 // Reorder index_1 to the end of src1:
2409
2410 // Reorder index_2 to the end of src2:
2411 const ReorderedIndexView<index_2,
2412 rank_2,
2415
2416 typename Tensor<rank_1 + rank_2 - 2,
2417 dim,
2419 result{};
2420 TensorAccessors::contract<1, rank_1, rank_2, dim>(result, reord_01, reord_02);
2421 return result;
2422}
2423
2424
2455template <int index_1,
2456 int index_2,
2457 int index_3,
2458 int index_4,
2459 int rank_1,
2460 int rank_2,
2461 int dim,
2462 typename Number,
2463 typename OtherNumber>
2464constexpr inline
2465 typename Tensor<rank_1 + rank_2 - 4,
2466 dim,
2467 typename ProductType<Number, OtherNumber>::type>::tensor_type
2470{
2471 Assert(0 <= index_1 && index_1 < rank_1,
2472 ExcMessage(
2473 "The specified index_1 must lie within the range [0,rank_1)"));
2474 Assert(0 <= index_3 && index_3 < rank_1,
2475 ExcMessage(
2476 "The specified index_3 must lie within the range [0,rank_1)"));
2477 Assert(index_1 != index_3,
2478 ExcMessage("index_1 and index_3 must not be the same"));
2479 Assert(0 <= index_2 && index_2 < rank_2,
2480 ExcMessage(
2481 "The specified index_2 must lie within the range [0,rank_2)"));
2482 Assert(0 <= index_4 && index_4 < rank_2,
2483 ExcMessage(
2484 "The specified index_4 must lie within the range [0,rank_2)"));
2485 Assert(index_2 != index_4,
2486 ExcMessage("index_2 and index_4 must not be the same"));
2487
2488 using namespace TensorAccessors;
2489 using namespace TensorAccessors::internal;
2490
2491 // Reorder index_1 to the end of src1:
2494
2495 // Reorder index_2 to the end of src2:
2498
2499 // Now, reorder index_3 to the end of src1. We have to make sure to
2500 // preserve the original ordering: index_1 has been removed. If
2501 // index_3 > index_1, we have to use (index_3 - 1) instead:
2503 (index_3 < index_1 ? index_3 : index_3 - 1),
2504 rank_1,
2505 ReorderedIndexView<index_1, rank_1, const Tensor<rank_1, dim, Number>>>
2506 reord_3 =
2507 TensorAccessors::reordered_index_view < index_3 < index_1 ? index_3 :
2508 index_3 - 1,
2509 rank_1 > (reord_1);
2510
2511 // Now, reorder index_4 to the end of src2. We have to make sure to
2512 // preserve the original ordering: index_2 has been removed. If
2513 // index_4 > index_2, we have to use (index_4 - 1) instead:
2515 (index_4 < index_2 ? index_4 : index_4 - 1),
2516 rank_2,
2518 reord_4 =
2519 TensorAccessors::reordered_index_view < index_4 < index_2 ? index_4 :
2520 index_4 - 1,
2521 rank_2 > (reord_2);
2522
2523 typename Tensor<rank_1 + rank_2 - 4,
2524 dim,
2526 result{};
2527 TensorAccessors::contract<2, rank_1, rank_2, dim>(result, reord_3, reord_4);
2528 return result;
2529}
2530
2531
2544template <int rank, int dim, typename Number, typename OtherNumber>
2545constexpr inline DEAL_II_ALWAYS_INLINE
2548 const Tensor<rank, dim, OtherNumber> &right)
2549{
2552 return result;
2553}
2554
2555
2573template <template <int, int, typename> class TensorT1,
2574 template <int, int, typename>
2575 class TensorT2,
2576 template <int, int, typename>
2577 class TensorT3,
2578 int rank_1,
2579 int rank_2,
2580 int dim,
2581 typename T1,
2582 typename T2,
2583 typename T3>
2584constexpr inline DEAL_II_ALWAYS_INLINE
2586 contract3(const TensorT1<rank_1, dim, T1> &left,
2587 const TensorT2<rank_1 + rank_2, dim, T2> &middle,
2588 const TensorT3<rank_2, dim, T3> &right)
2589{
2590 using return_type =
2593 middle,
2594 right);
2595}
2596
2597
2608template <int rank_1,
2609 int rank_2,
2610 int dim,
2611 typename Number,
2612 typename OtherNumber>
2613constexpr inline DEAL_II_ALWAYS_INLINE
2617{
2618 typename Tensor<rank_1 + rank_2,
2619 dim,
2621 result{};
2623 return result;
2624}
2625
2626
2634
2645template <int dim, typename Number>
2648{
2649 Assert(dim == 2, ExcInternalError());
2650
2652
2653 result[0] = src[1];
2654 result[1] = -src[0];
2655
2656 return result;
2657}
2658
2659
2669template <int dim, typename Number1, typename Number2>
2670constexpr inline DEAL_II_ALWAYS_INLINE
2673 const Tensor<1, dim, Number2> &src2)
2674{
2675 Assert(dim == 3, ExcInternalError());
2676
2678
2679 if constexpr (dim == 3)
2680 {
2681 result[0] = src1[1] * src2[2] - src1[2] * src2[1];
2682 result[1] = src1[2] * src2[0] - src1[0] * src2[2];
2683 result[2] = src1[0] * src2[1] - src1[1] * src2[0];
2684 }
2685
2686 return result;
2687}
2688
2689
2697
2703template <int dim, typename Number>
2704constexpr inline DEAL_II_ALWAYS_INLINE Number
2706{
2707 // Compute the determinant using the Laplace expansion of the
2708 // determinant. We expand along the last row.
2709 Number det = internal::NumberType<Number>::value(0.0);
2710
2711 for (unsigned int k = 0; k < dim; ++k)
2712 {
2713 Tensor<2, dim - 1, Number> minor;
2714 for (unsigned int i = 0; i < dim - 1; ++i)
2715 for (unsigned int j = 0; j < dim - 1; ++j)
2716 minor[i][j] = t[i][j < k ? j : j + 1];
2717
2718 const Number cofactor = ((k % 2 == 0) ? -1. : 1.) * determinant(minor);
2719
2720 det += t[dim - 1][k] * cofactor;
2721 }
2722
2723 return ((dim % 2 == 0) ? 1. : -1.) * det;
2724}
2725
2731template <typename Number>
2732constexpr DEAL_II_ALWAYS_INLINE Number
2734{
2735 return t[0][0];
2736}
2737
2743template <typename Number>
2744constexpr DEAL_II_ALWAYS_INLINE Number
2746{
2747 // hard-coded for efficiency reasons
2748 return t[0][0] * t[1][1] - t[1][0] * t[0][1];
2749}
2750
2756template <typename Number>
2757constexpr DEAL_II_ALWAYS_INLINE Number
2759{
2760 // hard-coded for efficiency reasons
2761 const Number C0 = internal::NumberType<Number>::value(t[1][1] * t[2][2]) -
2762 internal::NumberType<Number>::value(t[1][2] * t[2][1]);
2763 const Number C1 = internal::NumberType<Number>::value(t[1][2] * t[2][0]) -
2764 internal::NumberType<Number>::value(t[1][0] * t[2][2]);
2765 const Number C2 = internal::NumberType<Number>::value(t[1][0] * t[2][1]) -
2766 internal::NumberType<Number>::value(t[1][1] * t[2][0]);
2767 return t[0][0] * C0 + t[0][1] * C1 + t[0][2] * C2;
2768}
2769
2770
2777template <int dim, typename Number>
2778constexpr inline DEAL_II_ALWAYS_INLINE Number
2780{
2781 Number t = d[0][0];
2782 for (unsigned int i = 1; i < dim; ++i)
2783 t += d[i][i];
2784 return t;
2785}
2786
2787
2796template <int dim, typename Number>
2797constexpr inline Tensor<2, dim, Number>
2799{
2800 Number return_tensor[dim][dim];
2801
2802 // if desired, take over the
2803 // inversion of a 4x4 tensor
2804 // from the FullMatrix
2806
2807 return Tensor<2, dim, Number>(return_tensor);
2808}
2809
2810
2811#ifndef DOXYGEN
2812
2813template <typename Number>
2816{
2817 Tensor<2, 1, Number> return_tensor;
2818
2819 return_tensor[0][0] = internal::NumberType<Number>::value(1.0 / t[0][0]);
2820
2821 return return_tensor;
2822}
2823
2824
2825template <typename Number>
2828{
2829 Tensor<2, 2, Number> return_tensor;
2830
2831 const Number inv_det_t = internal::NumberType<Number>::value(
2832 1.0 / (t[0][0] * t[1][1] - t[1][0] * t[0][1]));
2833 return_tensor[0][0] = t[1][1];
2834 return_tensor[0][1] = -t[0][1];
2835 return_tensor[1][0] = -t[1][0];
2836 return_tensor[1][1] = t[0][0];
2837 return_tensor *= inv_det_t;
2838
2839 return return_tensor;
2840}
2841
2842template <typename Number>
2845{
2846 Tensor<2, 3, Number> return_tensor;
2847
2848 const auto value = [](const auto &t) {
2850 };
2851
2852 return_tensor[0][0] = value(t[1][1] * t[2][2]) - value(t[1][2] * t[2][1]);
2853 return_tensor[0][1] = value(t[0][2] * t[2][1]) - value(t[0][1] * t[2][2]);
2854 return_tensor[0][2] = value(t[0][1] * t[1][2]) - value(t[0][2] * t[1][1]);
2855 return_tensor[1][0] = value(t[1][2] * t[2][0]) - value(t[1][0] * t[2][2]);
2856 return_tensor[1][1] = value(t[0][0] * t[2][2]) - value(t[0][2] * t[2][0]);
2857 return_tensor[1][2] = value(t[0][2] * t[1][0]) - value(t[0][0] * t[1][2]);
2858 return_tensor[2][0] = value(t[1][0] * t[2][1]) - value(t[1][1] * t[2][0]);
2859 return_tensor[2][1] = value(t[0][1] * t[2][0]) - value(t[0][0] * t[2][1]);
2860 return_tensor[2][2] = value(t[0][0] * t[1][1]) - value(t[0][1] * t[1][0]);
2861
2862 const Number inv_det_t =
2863 value(1.0 / (t[0][0] * return_tensor[0][0] + t[0][1] * return_tensor[1][0] +
2864 t[0][2] * return_tensor[2][0]));
2865 return_tensor *= inv_det_t;
2866
2867 return return_tensor;
2868}
2869
2870#endif /* DOXYGEN */
2871
2872
2878template <int dim, typename Number>
2881{
2883 for (unsigned int i = 0; i < dim; ++i)
2884 {
2885 tt[i][i] = t[i][i];
2886 for (unsigned int j = i + 1; j < dim; ++j)
2887 {
2888 tt[i][j] = t[j][i];
2889 tt[j][i] = t[i][j];
2890 };
2891 }
2892 return tt;
2893}
2894
2895
2909template <int dim, typename Number>
2910constexpr Tensor<2, dim, Number>
2912{
2913 return determinant(t) * invert(t);
2914}
2915
2916
2930template <int dim, typename Number>
2931constexpr Tensor<2, dim, Number>
2933{
2934 return transpose(adjugate(t));
2935}
2936
2937
3001template <int dim, typename Number>
3004
3005
3013template <int dim, typename Number>
3014inline Number
3016{
3017 Number max = internal::NumberType<Number>::value(0.0);
3018 for (unsigned int j = 0; j < dim; ++j)
3019 {
3021 for (unsigned int i = 0; i < dim; ++i)
3023
3024 if (sum > max)
3025 max = sum;
3026 }
3027
3028 return max;
3029}
3030
3031
3039template <int dim, typename Number>
3040inline Number
3042{
3043 Number max = internal::NumberType<Number>::value(0.0);
3044 for (unsigned int i = 0; i < dim; ++i)
3045 {
3047 for (unsigned int j = 0; j < dim; ++j)
3049
3050 if (sum > max)
3051 max = sum;
3052 }
3053
3054 return max;
3055}
3056
3060
3061
3062#ifndef DOXYGEN
3063
3064
3065# ifdef DEAL_II_ADOLC_WITH_ADVANCED_BRANCHING
3066
3067// Specialization of functions for ADOL-C number types when
3068// the advanced branching feature is used
3069template <int dim>
3070inline adouble
3072{
3073 adouble max = internal::NumberType<adouble>::value(0.0);
3074 for (unsigned int j = 0; j < dim; ++j)
3075 {
3076 adouble sum = internal::NumberType<adouble>::value(0.0);
3077 for (unsigned int i = 0; i < dim; ++i)
3078 sum += fabs(t[i][j]);
3079
3080 condassign(max, (sum > max), sum, max);
3081 }
3082
3083 return max;
3084}
3085
3086
3087template <int dim>
3088inline adouble
3090{
3092 for (unsigned int i = 0; i < dim; ++i)
3093 {
3095 for (unsigned int j = 0; j < dim; ++j)
3096 sum += fabs(t[i][j]);
3097
3098 condassign(max, (sum > max), sum, max);
3099 }
3100
3101 return max;
3102}
3103
3104# endif // DEAL_II_ADOLC_WITH_ADVANCED_BRANCHING
3105
3106
3107#endif // DOXYGEN
3108
3110
3111#endif
std::size_t size() const
Definition array_view.h:689
Definition point.h:113
constexpr Tensor & operator*=(const OtherNumber &factor)
constexpr Tensor & operator=(const OtherNumber &d) &&=delete
static constexpr unsigned int n_independent_components
Definition tensor.h:119
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
friend class Tensor
Definition tensor.h:383
static constexpr unsigned int rank
Definition tensor.h:114
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:129
constexpr Tensor & operator=(const OtherNumber &d) &
static constexpr unsigned int dimension
Definition tensor.h:109
constexpr Tensor operator-() const
constexpr Tensor & operator/=(const OtherNumber &factor)
constexpr Tensor(const ArrayView< ElementType, MemorySpace > &initializer)
constexpr Tensor< 2, dim, Number > cofactor(const Tensor< 2, dim, Number > &t)
Definition tensor.h:2932
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:2146
constexpr Tensor(const Tensor< 1, dim, Tensor< rank_ - 1, dim, OtherNumber > > &initializer)
constexpr Tensor< rank_1+rank_2, dim, typename ProductType< Number, OtherNumber >::type > outer_product(const Tensor< rank_1, dim, Number > &src1, const Tensor< rank_2, dim, OtherNumber > &src2)
Definition tensor.h:2615
constexpr Tensor< 2, dim, Number > adjugate(const Tensor< 2, dim, Number > &t)
Definition tensor.h:2911
constexpr const Number & operator[](const TableIndices< rank_ > &indices) const
constexpr ProductType< T1, typenameProductType< T2, T3 >::type >::type contract3(const TensorT1< rank_1, dim, T1 > &left, const TensorT2< rank_1+rank_2, dim, T2 > &middle, const TensorT3< rank_2, dim, T3 > &right)
Definition tensor.h:2586
constexpr Tensor< 2, dim, Number > transpose(const Tensor< 2, dim, Number > &t)
Definition tensor.h:2880
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:520
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:2072
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:2039
Number * begin_raw()
static constexpr unsigned int rank
Definition tensor.h:482
constexpr Number determinant(const Tensor< 2, dim, Number > &t)
Definition tensor.h:2705
std::conditional_t< rank_==1, Number, Tensor< rank_ - 1, dim, Number > > value_type
Definition tensor.h:506
constexpr Tensor(const Tensor< rank_, dim, OtherNumber > &initializer)
Tensor< rank, dim, Number > sum(const Tensor< rank, dim, Number > &local, const MPI_Comm mpi_communicator)
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:2018
const Number * begin_raw() const
constexpr bool operator!=(const Tensor< rank_, dim, OtherNumber > &) const
constexpr ProductType< Number, OtherNumber >::type scalar_product(const Tensor< rank, dim, Number > &left, const Tensor< rank, dim, OtherNumber > &right)
Definition tensor.h:2547
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:2204
constexpr value_type & operator[](const unsigned int i)
Number * end_raw()
friend class Tensor
Definition tensor.h:866
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:2166
Number linfty_norm(const Tensor< 2, dim, Number > &t)
Definition tensor.h:3041
constexpr ProductType< Other, Number >::type operator*(const Other &object, const Tensor< 0, dim, Number > &t)
Definition tensor.h:1978
constexpr Tensor< rank_1+rank_2-4, dim, typenameProductType< Number, OtherNumber >::type >::tensor_type double_contract(const Tensor< rank_1, dim, Number > &src1, const Tensor< rank_2, dim, OtherNumber > &src2)
Definition tensor.h:2468
Tensor< 2, dim, Number > project_onto_orthogonal_tensors(const Tensor< 2, dim, Number > &A)
Number l1_norm(const Tensor< 2, dim, Number > &t)
Definition tensor.h:3015
constexpr Number trace(const Tensor< 2, dim, Number > &d)
Definition tensor.h:2779
static constexpr unsigned int dimension
Definition tensor.h:477
static constexpr TableIndices< rank_ > unrolled_to_component_indices(const unsigned int i)
constexpr Tensor< 1, dim, Number > cross_product_2d(const Tensor< 1, dim, Number > &src)
Definition tensor.h:2647
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:2123
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:852
constexpr Number determinant(const Tensor< 2, 1, Number > &t)
Definition tensor.h:2733
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:2055
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:2233
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:2187
Tensor< rank_, dim, Number > tensor_type
Definition tensor.h:835
constexpr ProductType< Number, Other >::type operator*(const Tensor< 0, dim, Number > &t, const Other &object)
Definition tensor.h:1998
constexpr Tensor(const ArrayLike &initializer, std::index_sequence< Indices... >)
constexpr Number determinant(const Tensor< 2, 2, Number > &t)
Definition tensor.h:2745
constexpr Tensor< rank_1+rank_2-2, dim, typenameProductType< Number, OtherNumber >::type >::tensor_type contract(const Tensor< rank_1, dim, Number > &src1, const Tensor< rank_2, dim, OtherNumber > &src2)
Definition tensor.h:2393
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:2097
constexpr Tensor< 2, dim, Number > invert(const Tensor< 2, dim, Number > &)
Definition tensor.h:2798
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 Number determinant(const Tensor< 2, 3, Number > &t)
Definition tensor.h:2758
constexpr Tensor< rank_1+rank_2-2, dim, typenameProductType< Number, OtherNumber >::type >::tensor_type operator*(const Tensor< rank_1, dim, Number > &src1, const Tensor< rank_2, dim, OtherNumber > &src2)
Definition tensor.h:2299
constexpr Tensor(const array_type &initializer)
static constexpr unsigned int n_independent_components
Definition tensor.h:498
constexpr Tensor operator-() const
constexpr Tensor< 1, dim, typename ProductType< Number1, Number2 >::type > cross_product_3d(const Tensor< 1, dim, Number1 > &src1, const Tensor< 1, dim, Number2 > &src2)
Definition tensor.h:2672
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:286
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:40
#define DEAL_II_CXX20_REQUIRES(condition)
Definition config.h:248
#define DEAL_II_CXX23_ASSUME(expr)
Definition config.h:265
#define DEAL_II_HOST_DEVICE
Definition config.h:171
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:41
#define DEAL_II_HOST_DEVICE_ALWAYS_INLINE
Definition config.h:172
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)
const bool IsBlockVector< VectorType >::value
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)
constexpr ReturnType< rank, T >::value_type & extract(T &t, const ArrayType &indices)
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)
VectorType::value_type * begin(VectorType &V)
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:873
constexpr bool value_is_zero(const Number &value)
Definition numbers.h:881
constexpr bool values_are_equal(const Number1 &value_1, const Number2 &value_2)
Definition numbers.h:865
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:668
decltype(std::declval< T >() *std::declval< U >()) type
static real_type abs(const number &x)
Definition numbers.h:558
static constexpr real_type abs_square(const number &x)
Definition numbers.h:550
constexpr Tensor< 2, dim, Number > adjugate(const Tensor< 2, dim, Number > &t)
Definition tensor.h:2911
std::ostream & operator<<(std::ostream &out, const Tensor< rank_, dim, Number > &p)
Definition tensor.h:1928
constexpr Tensor< 2, dim, Number > transpose(const Tensor< 2, dim, Number > &t)
Definition tensor.h:2880
constexpr Number determinant(const Tensor< 2, dim, Number > &t)
Definition tensor.h:2705
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:2204
Number linfty_norm(const Tensor< 2, dim, Number > &t)
Definition tensor.h:3041
Number l1_norm(const Tensor< 2, dim, Number > &t)
Definition tensor.h:3015
constexpr Tensor< 2, dim, Number > invert(const Tensor< 2, dim, Number > &)
Definition tensor.h:2798