deal.II version GIT relicensing-1838-g97284be5cd 2024-09-11 15:30:00+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
tensor.h
Go to the documentation of this file.
1// ------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4// Copyright (C) 1998 - 2024 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Part of the source code is dual licensed under Apache-2.0 WITH
9// LLVM-exception OR LGPL-2.1-or-later. Detailed license information
10// governing the source code and code contributions can be found in
11// LICENSE.md and CONTRIBUTING.md at the top level directory of deal.II.
12//
13// ------------------------------------------------------------------------
14
15#ifndef dealii_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#ifdef DEAL_II_WITH_ADOLC
28# include <adolc/adouble.h> // Taped double
29#endif
30
31// boost::serialization::make_array used to be in array.hpp, but was
32// moved to a different file in BOOST 1.64
33#include <boost/version.hpp>
34#if BOOST_VERSION >= 106400
35# include <boost/serialization/array_wrapper.hpp>
36#else
37# include <boost/serialization/array.hpp>
38#endif
39
40
41#include <array>
42#include <cmath>
43#include <ostream>
44#include <type_traits>
45
47
48// Forward declarations:
49#ifndef DOXYGEN
50template <typename ElementType, typename MemorySpace>
51class ArrayView;
52
53template <int dim, typename Number>
55class Point;
56
57template <int rank_, int dim, typename Number = double>
58class Tensor;
59template <typename Number>
60class Vector;
61template <typename number>
62class FullMatrix;
63namespace Differentiation
64{
65 namespace SD
66 {
67 class Expression;
68 }
69} // namespace Differentiation
70#endif
71
72
102template <int dim, typename Number>
103class Tensor<0, dim, Number>
104{
105public:
106 static_assert(dim >= 0,
107 "Tensors must have a dimension greater than or equal to one.");
108
117 static constexpr unsigned int dimension = dim;
118
122 static constexpr unsigned int rank = 0;
123
127 static constexpr unsigned int n_independent_components = 1;
128
138
143 using value_type = Number;
144
150 using array_type = Number;
151
157 constexpr DEAL_II_HOST_DEVICE
159
167 template <typename OtherNumber>
168 constexpr DEAL_II_HOST_DEVICE
170
176 template <typename OtherNumber>
177 constexpr DEAL_II_HOST_DEVICE
178 Tensor(const OtherNumber &initializer);
179
180#ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
184 constexpr DEAL_II_HOST_DEVICE
185 Tensor(const Tensor<0, dim, Number> &other);
186
190 constexpr DEAL_II_HOST_DEVICE
191 Tensor(Tensor<0, dim, Number> &&other) noexcept;
192#endif
193
203 constexpr DEAL_II_HOST_DEVICE
204 operator Number &();
205
214 constexpr DEAL_II_HOST_DEVICE operator const Number &() const;
215
223 template <typename OtherNumber>
224 constexpr DEAL_II_HOST_DEVICE Tensor &
226
227#if defined(__INTEL_COMPILER) || defined(DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG)
236 constexpr DEAL_II_HOST_DEVICE Tensor &
238#endif
239
240#ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
245 operator=(Tensor<0, dim, Number> &&other) noexcept;
246#endif
247
254 template <typename OtherNumber>
255 constexpr DEAL_II_HOST_DEVICE Tensor &
256 operator=(const OtherNumber &d) &;
257
263 template <typename OtherNumber>
264 constexpr DEAL_II_HOST_DEVICE Tensor &
265 operator=(const OtherNumber &d) && = delete;
266
270 template <typename OtherNumber>
271 constexpr bool
273
277 template <typename OtherNumber>
278 constexpr bool
280
286 template <typename OtherNumber>
287 constexpr DEAL_II_HOST_DEVICE Tensor &
289
295 template <typename OtherNumber>
296 constexpr DEAL_II_HOST_DEVICE Tensor &
298
304 template <typename OtherNumber>
305 constexpr DEAL_II_HOST_DEVICE Tensor &
306 operator*=(const OtherNumber &factor);
307
313 template <typename OtherNumber>
314 constexpr DEAL_II_HOST_DEVICE Tensor &
315 operator/=(const OtherNumber &factor);
316
323 operator-() const;
324
337 constexpr void
339
346 norm() const;
347
355 norm_square() const;
356
364 template <class Iterator>
365 void
366 unroll(const Iterator begin, const Iterator end) const;
367
373 template <class Archive>
374 void
375 serialize(Archive &ar, const unsigned int version);
376
381 using tensor_type = Number;
382
383private:
387 Number value;
388
389 // Allow an arbitrary Tensor to access the underlying values.
390 template <int, int, typename>
391 friend class Tensor;
392};
393
394
395
469template <int rank_, int dim, typename Number>
471{
472public:
473 static_assert(rank_ >= 1,
474 "Tensors must have a rank greater than or equal to one.");
475 static_assert(dim >= 0,
476 "Tensors must have a dimension greater than or equal to zero.");
485 static constexpr unsigned int dimension = dim;
486
490 static constexpr unsigned int rank = rank_;
491
506 static constexpr unsigned int n_independent_components =
507 Tensor<rank_ - 1, dim>::n_independent_components * dim;
508
515 std::conditional_t<rank_ == 1, Number, Tensor<rank_ - 1, dim, Number>>;
516
528 using array_type = std::conditional_t<
529 rank_ == 1,
530 Number[(dim != 0) ? dim : 1],
531 typename Tensor<rank_ - 1, dim, Number>::array_type[(dim != 0) ? dim : 1]>;
532
540
546 constexpr DEAL_II_HOST_DEVICE explicit Tensor(const array_type &initializer);
547
560 template <typename ElementType, typename MemorySpace>
561 constexpr DEAL_II_HOST_DEVICE explicit Tensor(
562 const ArrayView<ElementType, MemorySpace> &initializer);
563
571 template <typename OtherNumber>
572 constexpr DEAL_II_HOST_DEVICE
574
578 template <typename OtherNumber>
579 constexpr Tensor(
580 const Tensor<1, dim, Tensor<rank_ - 1, dim, OtherNumber>> &initializer);
581
585 template <typename OtherNumber>
586 constexpr
587 operator Tensor<1, dim, Tensor<rank_ - 1, dim, OtherNumber>>() const;
588
589#ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
593 constexpr Tensor(const Tensor<rank_, dim, Number> &);
594
598 constexpr Tensor(Tensor<rank_, dim, Number> &&) noexcept;
599#endif
600
607 operator[](const unsigned int i);
608
614 constexpr DEAL_II_HOST_DEVICE const value_type &
615 operator[](const unsigned int i) const;
616
620 constexpr const Number &
621 operator[](const TableIndices<rank_> &indices) const;
622
626 constexpr Number &
628
633 Number *
635
640 const Number *
641 begin_raw() const;
642
647 Number *
649
654 const Number *
655 end_raw() const;
656
664 template <typename OtherNumber>
665 constexpr DEAL_II_HOST_DEVICE Tensor &
667
674 constexpr DEAL_II_HOST_DEVICE Tensor &
675 operator=(const Number &d) &;
676
682 constexpr DEAL_II_HOST_DEVICE Tensor &
683 operator=(const Number &d) && = delete;
684
685#ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
691
697#endif
698
702 template <typename OtherNumber>
703 constexpr bool
705
709 template <typename OtherNumber>
710 constexpr bool
712
718 template <typename OtherNumber>
719 constexpr DEAL_II_HOST_DEVICE Tensor &
721
727 template <typename OtherNumber>
728 constexpr DEAL_II_HOST_DEVICE Tensor &
730
737 template <typename OtherNumber>
738 constexpr DEAL_II_HOST_DEVICE Tensor &
739 operator*=(const OtherNumber &factor);
740
746 template <typename OtherNumber>
747 constexpr DEAL_II_HOST_DEVICE Tensor &
748 operator/=(const OtherNumber &factor);
749
756 operator-() const;
757
770 constexpr void
772
782 norm() const;
783
790 constexpr DEAL_II_HOST_DEVICE
792 norm_square() const;
793
804 template <class Iterator>
805 void
806 unroll(const Iterator begin, const Iterator end) const;
807
812 static constexpr DEAL_II_HOST_DEVICE unsigned int
814
821 unrolled_to_component_indices(const unsigned int i);
822
827 static constexpr std::size_t
829
835 template <class Archive>
836 void
837 serialize(Archive &ar, const unsigned int version);
838
844
845private:
851 std::conditional_t<rank_ == 1,
852 std::array<Number, dim>,
853 std::array<Tensor<rank_ - 1, dim, Number>, dim>>
855
862 template <typename ArrayLike, std::size_t... Indices>
863 constexpr DEAL_II_HOST_DEVICE
864 Tensor(const ArrayLike &initializer, std::index_sequence<Indices...>);
865
866 // Allow an arbitrary Tensor to access the underlying values.
867 template <int, int, typename>
868 friend class Tensor;
869
870 // Point is allowed access to the coordinates. This is supposed to improve
871 // speed.
872 friend class Point<dim, Number>;
873};
874
875
876#ifndef DOXYGEN
877namespace internal
878{
879 // Workaround: The following 4 overloads are necessary to be able to
880 // compile the library with Apple Clang 8 and older. We should remove
881 // these overloads again when we bump the minimal required version to
882 // something later than clang-3.6 / Apple Clang 6.3.
883 template <int rank, int dim, typename T, typename U>
884 struct ProductTypeImpl<Tensor<rank, dim, T>, std::complex<U>>
885 {
886 using type =
888 };
889
890 template <int rank, int dim, typename T, typename U>
891 struct ProductTypeImpl<Tensor<rank, dim, std::complex<T>>, std::complex<U>>
892 {
893 using type =
895 };
896
897 template <typename T, int rank, int dim, typename U>
898 struct ProductTypeImpl<std::complex<T>, Tensor<rank, dim, U>>
899 {
900 using type =
902 };
903
904 template <int rank, int dim, typename T, typename U>
905 struct ProductTypeImpl<std::complex<T>, Tensor<rank, dim, std::complex<U>>>
906 {
907 using type =
909 };
910 // end workaround
911
916 template <int rank, int dim, typename T>
917 struct NumberType<Tensor<rank, dim, T>>
918 {
919 static constexpr DEAL_II_HOST_DEVICE_ALWAYS_INLINE const
922 {
923 return t;
924 }
925
927 value(const T &t)
928 {
930 tmp = t;
931 return tmp;
932 }
933 };
934} // namespace internal
935
936
937/*---------------------- Inline functions: Tensor<0,dim> ---------------------*/
938
939
940template <int dim, typename Number>
943 // Some auto-differentiable numbers need explicit
944 // zero initialization such as adtl::adouble.
945 : Tensor{0.0}
946{}
947
948
949
950template <int dim, typename Number>
951template <typename OtherNumber>
953Tensor<0, dim, Number>::Tensor(const OtherNumber &initializer)
954 : value(internal::NumberType<Number>::value(initializer))
955{}
956
957
958
959template <int dim, typename Number>
960template <typename OtherNumber>
963 : Tensor{p.value}
964{}
965
966
967# ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
968template <int dim, typename Number>
971 : value{other.value}
972{}
973
974
975
976template <int dim, typename Number>
979 : value{std::move(other.value)}
980{}
981# endif
982
983
984
985template <int dim, typename Number>
988{
989 Assert(dim != 0,
990 ExcMessage("Cannot access an object of type Tensor<0,0,Number>"));
991 return value;
992}
993
994
995template <int dim, typename Number>
996constexpr inline DEAL_II_ALWAYS_INLINE
998{
999 Assert(dim != 0,
1000 ExcMessage("Cannot access an object of type Tensor<0,0,Number>"));
1001 return value;
1002}
1003
1004
1005
1006template <int dim, typename Number>
1007template <typename OtherNumber>
1010{
1012 return *this;
1013}
1014
1015
1016# if defined(__INTEL_COMPILER) || defined(DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG)
1017template <int dim, typename Number>
1020{
1021 value = p.value;
1022 return *this;
1023}
1024# endif
1025
1026# ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
1027template <int dim, typename Number>
1030{
1031 value = std::move(other.value);
1032 return *this;
1033}
1034# endif
1035
1036
1037
1038template <int dim, typename Number>
1039template <typename OtherNumber>
1041Tensor<0, dim, Number>::operator=(const OtherNumber &d) &
1042{
1044 return *this;
1045}
1046
1047
1048template <int dim, typename Number>
1049template <typename OtherNumber>
1050constexpr inline bool
1052{
1053# ifdef DEAL_II_ADOLC_WITH_ADVANCED_BRANCHING
1054 Assert(!(std::is_same_v<Number, adouble> ||
1055 std::is_same_v<OtherNumber, adouble>),
1056 ExcMessage(
1057 "The Tensor equality operator for ADOL-C taped numbers has not yet "
1058 "been extended to support advanced branching."));
1059# endif
1060
1061 return numbers::values_are_equal(value, p.value);
1062}
1063
1064
1065template <int dim, typename Number>
1066template <typename OtherNumber>
1067constexpr bool
1069{
1070 return !((*this) == p);
1071}
1072
1073
1074template <int dim, typename Number>
1075template <typename OtherNumber>
1078{
1079 value += p.value;
1080 return *this;
1081}
1082
1083
1084template <int dim, typename Number>
1085template <typename OtherNumber>
1088{
1089 value -= p.value;
1090 return *this;
1091}
1092
1093
1094
1095namespace internal
1096{
1097 namespace ComplexWorkaround
1098 {
1099 template <typename Number, typename OtherNumber>
1101 multiply_assign_scalar(Number &val, const OtherNumber &s)
1102 {
1103 val *= s;
1104 }
1105
1106 template <typename Number, typename OtherNumber>
1108 multiply_assign_scalar(std::complex<Number> &val, const OtherNumber &s)
1109 {
1110# if KOKKOS_VERSION >= 30600
1111 KOKKOS_IF_ON_HOST((val *= s;))
1112 KOKKOS_IF_ON_DEVICE(({
1113 (void)val;
1114 (void)s;
1115 Kokkos::abort(
1116 "This function is not implemented for std::complex<Number>!\n");
1117 }))
1118# else
1119# ifdef KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST
1120 val *= s;
1121# else
1122 (void)val;
1123 (void)s;
1124 Kokkos::abort(
1125 "This function is not implemented for std::complex<Number>!\n");
1126# endif
1127# endif
1128 }
1129 } // namespace ComplexWorkaround
1130} // namespace internal
1131
1132
1133template <int dim, typename Number>
1134template <typename OtherNumber>
1136Tensor<0, dim, Number>::operator*=(const OtherNumber &s)
1137{
1138 internal::ComplexWorkaround::multiply_assign_scalar(value, s);
1139 return *this;
1140}
1141
1142
1143
1144template <int dim, typename Number>
1145template <typename OtherNumber>
1147Tensor<0, dim, Number>::operator/=(const OtherNumber &s)
1148{
1149 value /= s;
1150 return *this;
1151}
1152
1153
1154template <int dim, typename Number>
1157{
1158 return -value;
1159}
1160
1161
1162template <int dim, typename Number>
1165{
1166 Assert(dim != 0,
1167 ExcMessage("Cannot access an object of type Tensor<0,0,Number>"));
1169}
1170
1171
1172template <int dim, typename Number>
1176{
1177 Assert(dim != 0,
1178 ExcMessage("Cannot access an object of type Tensor<0,0,Number>"));
1180}
1181
1182
1183
1184template <int dim, typename Number>
1185constexpr inline void
1187{
1188 // Some auto-differentiable numbers need explicit
1189 // zero initialization.
1191}
1192
1193
1194
1195template <int dim, typename Number>
1196template <class Iterator>
1197inline void
1198Tensor<0, dim, Number>::unroll(const Iterator begin, const Iterator end) const
1199{
1200 (void)end;
1201 AssertDimension(std::distance(begin, end), n_independent_components);
1202 Assert(dim != 0,
1203 ExcMessage("Cannot unroll an object of type Tensor<0,0,Number>"));
1204 Assert(std::distance(begin, end) >= 1,
1205 ExcMessage("The provided iterator range must contain at least one "
1206 "element."));
1207 *begin = value;
1208}
1209
1210
1211
1212template <int dim, typename Number>
1213template <class Archive>
1214inline void
1215Tensor<0, dim, Number>::serialize(Archive &ar, const unsigned int)
1216{
1217 ar &value;
1218}
1219
1220
1221template <int dim, typename Number>
1223
1224
1225/*-------------------- Inline functions: Tensor<rank,dim> --------------------*/
1226
1227template <int rank_, int dim, typename Number>
1228template <typename ArrayLike, std::size_t... indices>
1230Tensor<rank_, dim, Number>::Tensor(const ArrayLike &initializer,
1231 std::index_sequence<indices...>)
1232 // Extract from the 'initializer' a sequence of elements via template
1233 // pack evaluation. This could be as easy as
1234 // values{{ (initializer[indices])... }}
1235 // but of course in practice it is not. The challenge is that if rank>1,
1236 // we want to pass the elements initializer[indices] down to the next
1237 // lower rank tensor for evaluation unchanged. But at the rank==1 level,
1238 // we need to convert to the scalar type 'Number'. This would all be
1239 // relatively straightforward if we could rely on automatic type
1240 // conversion, but for some autodifferentiation types, the conversion
1241 // from the AD to double (i.e., the extraction of a scalar value) is
1242 // not implicit, and we need to call internal::NumberType<Number>::value() --
1243 // but as mentioned, we can only do that for rank==1.
1244 //
1245 // We can achieve all of this by dispatching to a lambda function within
1246 // which we can use a 'if constexpr'.
1247 : values{{([&initializer]() -> value_type {
1248 if constexpr (rank_ == 1)
1249 return internal::NumberType<Number>::value(initializer[indices]);
1250 else
1251 return value_type(initializer[indices]);
1252 }())...}}
1253{
1254 static_assert(sizeof...(indices) == dim,
1255 "dim should match the number of indices");
1256}
1257
1258
1259# ifdef DEAL_II_HAVE_CXX20
1260
1261template <int rank_, int dim, typename Number>
1264 : values(
1265 // In order to initialize the std::array<Number,dim>, we would need a
1266 // brace-enclosed list of length 'dim'. There is no way in C++ to create
1267 // such a list in-place, but we can come up with a lambda function that
1268 // expands such a list via template-pack expansion, and then uses this
1269 // list to initialize a std::array which it then returns.
1270 //
1271 // The trick to come up with such a lambda function is to have a function
1272 // that takes an argument that depends on a template-pack of integers.
1273 // We will call the function with an integer list of length 'dim', and
1274 // in the function itself expand that pack in a way that it serves as
1275 // a brace-enclosed list of initializers for a std::array.
1276 //
1277 // Of course, we do not want to initialize the array with the integers,
1278 // but with zeros. (Or, more correctly, a zero of the element type.)
1279 // The canonical way to do this would be using the comma operator:
1280 // (sequence_element, 0.0)
1281 // returns zero, and
1282 // (sequence, 0.0)...
1283 // returns a list of zeros of the right length. Unfortunately, some
1284 // compilers then warn that the left side of the comma expression has
1285 // no effect -- well, bummer, that was of course exactly the idea.
1286 // We could work around this by using
1287 // (sequence_element * 0.0)
1288 // instead, assuming that the compiler will optimize (known) integer
1289 // times zero to zero, and similarly for (known) integer times times
1290 // default-initialized tensor.
1291 //
1292 // But, instead of relying on compiler optimizations, a better way is
1293 // to simply have another (nested) lambda function that takes the
1294 // integer sequence element as an argument and ignores it, just
1295 // returning a zero instead.
1296 []<std::size_t... I>(
1297 const std::index_sequence<I...> &) constexpr -> decltype(values) {
1298 if constexpr (rank_ == 1)
1299 {
1300 auto get_zero_and_ignore_argument = [](int) {
1302 };
1303 return {{(get_zero_and_ignore_argument(I))...}};
1304 }
1305 else
1306 {
1307 auto get_zero_and_ignore_argument = [](int) {
1308 return Tensor<rank_ - 1, dim, Number>();
1309 };
1310 return {{(get_zero_and_ignore_argument(I))...}};
1311 }
1312 }(std::make_index_sequence<dim>()))
1313{}
1314
1315# else
1316
1317// The C++17 case works in essence the same, except that we can't use a
1318// lambda function with explicit template parameters, i.e., we can't do
1319// []<std::size_t... I>(const std::index_sequence<I...> &)
1320// as above because that's a C++20 feature. Lambda functions in C++17 can
1321// have template packs as arguments, but we need the ability to *name*
1322// that template pack (the 'I' above) and that's not possible in C++17.
1323//
1324// We work around this by moving the lambda function to a global function
1325// and using the traditional template syntax on it.
1326namespace internal
1327{
1328 namespace TensorInitialization
1329 {
1330 template <int rank, int dim, typename Number, std::size_t... I>
1331 constexpr std::array<typename Tensor<rank, dim, Number>::value_type, dim>
1332 make_zero_array(const std::index_sequence<I...> &)
1333 {
1334 static_assert(sizeof...(I) == dim, "This is bad.");
1335
1336 // First peel off the case dim==0. If we don't, some compilers
1337 // will warn below that we define these lambda functions but
1338 // never use them (because the expanded list has zero elements,
1339 // and the get_zero_and_ignore_argument() function is not used...)
1340 if constexpr (dim == 0)
1341 {
1342 return {};
1343 }
1344 else if constexpr (rank == 1)
1345 {
1346 auto get_zero_and_ignore_argument = [](int) {
1348 };
1349 return {{(get_zero_and_ignore_argument(I))...}};
1350 }
1351 else
1352 {
1353 auto get_zero_and_ignore_argument = [](int) {
1354 return Tensor<rank - 1, dim, Number>();
1355 };
1356 return {{(get_zero_and_ignore_argument(I))...}};
1357 }
1358 }
1359 } // namespace TensorInitialization
1360} // namespace internal
1361
1362
1363template <int rank_, int dim, typename Number>
1366 : values(internal::TensorInitialization::make_zero_array<rank_, dim, Number>(
1367 std::make_index_sequence<dim>()))
1368{}
1369
1370
1371# endif
1372
1373
1374template <int rank_, int dim, typename Number>
1376Tensor<rank_, dim, Number>::Tensor(const array_type &initializer)
1377 : Tensor(initializer, std::make_index_sequence<dim>{})
1378{}
1379
1380
1381
1382template <int rank_, int dim, typename Number>
1383template <typename ElementType, typename MemorySpace>
1386 const ArrayView<ElementType, MemorySpace> &initializer)
1387{
1388 // make nvcc happy
1389 const int my_n_independent_components = n_independent_components;
1390 AssertDimension(initializer.size(), my_n_independent_components);
1391
1392 for (unsigned int i = 0; i < my_n_independent_components; ++i)
1393 (*this)[unrolled_to_component_indices(i)] = initializer[i];
1394}
1395
1396
1397
1398template <int rank_, int dim, typename Number>
1399template <typename OtherNumber>
1402 const Tensor<rank_, dim, OtherNumber> &initializer)
1403 : Tensor(initializer, std::make_index_sequence<dim>{})
1404{}
1405
1406
1407
1408template <int rank_, int dim, typename Number>
1409template <typename OtherNumber>
1410constexpr DEAL_II_ALWAYS_INLINE
1412 const Tensor<1, dim, Tensor<rank_ - 1, dim, OtherNumber>> &initializer)
1413 : Tensor(initializer, std::make_index_sequence<dim>{})
1414{}
1415
1416
1417
1418template <int rank_, int dim, typename Number>
1419template <typename OtherNumber>
1421operator Tensor<1, dim, Tensor<rank_ - 1, dim, OtherNumber>>() const
1422{
1423 Tensor<1, dim, Tensor<rank_ - 1, dim, OtherNumber>> x;
1424 std::copy(values.begin(), values.end(), x.values.begin());
1425 return x;
1426}
1427
1428
1429# ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
1430template <int rank_, int dim, typename Number>
1431constexpr DEAL_II_ALWAYS_INLINE
1433 : values(other.values)
1434{}
1435
1436
1437
1438template <int rank_, int dim, typename Number>
1439constexpr DEAL_II_ALWAYS_INLINE
1441 : values(std::move(other.values))
1442{}
1443# endif
1444
1445
1446
1447template <int rank_, int dim, typename Number>
1450 Tensor<rank_, dim, Number>::operator[](const unsigned int i)
1451{
1452 Assert(dim != 0,
1453 ExcMessage("Cannot access an object of type Tensor<rank_,0,Number>"));
1454 AssertIndexRange(i, dim);
1455 DEAL_II_CXX23_ASSUME(i < dim);
1456
1457 return values[i];
1458}
1459
1460
1461template <int rank_, int dim, typename Number>
1462constexpr DEAL_II_ALWAYS_INLINE
1464 Tensor<rank_, dim, Number>::operator[](const unsigned int i) const
1465{
1466 Assert(dim != 0,
1467 ExcMessage("Cannot access an object of type Tensor<rank_,0,Number>"));
1468 AssertIndexRange(i, dim);
1469 DEAL_II_CXX23_ASSUME(i < dim);
1470
1471 return values[i];
1472}
1473
1474
1475template <int rank_, int dim, typename Number>
1476constexpr inline DEAL_II_ALWAYS_INLINE const Number &
1478{
1479 Assert(dim != 0,
1480 ExcMessage("Cannot access an object of type Tensor<rank_,0,Number>"));
1481
1482 return TensorAccessors::extract<rank_>(*this, indices);
1483}
1484
1485
1486
1487template <int rank_, int dim, typename Number>
1488constexpr inline DEAL_II_ALWAYS_INLINE Number &
1490{
1491 Assert(dim != 0,
1492 ExcMessage("Cannot access an object of type Tensor<rank_,0,Number>"));
1493
1494 return TensorAccessors::extract<rank_>(*this, indices);
1495}
1496
1497
1498
1499template <int rank_, int dim, typename Number>
1500inline Number *
1502{
1503 static_assert(rank_ == 1,
1504 "This function is only available for rank-1 tensors "
1505 "because higher-rank tensors may not store their elements "
1506 "in a contiguous array.");
1507
1508 return std::addressof(
1509 this->operator[](this->unrolled_to_component_indices(0)));
1510}
1511
1512
1513
1514template <int rank_, int dim, typename Number>
1515inline const Number *
1517{
1518 static_assert(rank_ == 1,
1519 "This function is only available for rank-1 tensors "
1520 "because higher-rank tensors may not store their elements "
1521 "in a contiguous array.");
1522
1523 return std::addressof(
1524 this->operator[](this->unrolled_to_component_indices(0)));
1525}
1526
1527
1528
1529template <int rank_, int dim, typename Number>
1530inline Number *
1532{
1533 static_assert(rank_ == 1,
1534 "This function is only available for rank-1 tensors "
1535 "because higher-rank tensors may not store their elements "
1536 "in a contiguous array.");
1537
1538 return begin_raw() + n_independent_components;
1539}
1540
1541
1542
1543template <int rank_, int dim, typename Number>
1544inline const Number *
1546{
1547 static_assert(rank_ == 1,
1548 "This function is only available for rank-1 tensors "
1549 "because higher-rank tensors may not store their elements "
1550 "in a contiguous array.");
1551
1552 return begin_raw() + n_independent_components;
1553}
1554
1555
1556
1557template <int rank_, int dim, typename Number>
1558template <typename OtherNumber>
1561{
1562 // The following loop could be written more concisely using std::copy, but
1563 // that function is only constexpr from C++20 on.
1564 for (unsigned int i = 0; i < dim; ++i)
1565 values[i] = t.values[i];
1566 return *this;
1567}
1568
1569
1570
1571template <int rank_, int dim, typename Number>
1574 Tensor<rank_, dim, Number>::operator=(const Number &d) &
1575{
1577 (void)d;
1578
1579 for (unsigned int i = 0; i < dim; ++i)
1580 values[i] = internal::NumberType<Number>::value(0.0);
1581 return *this;
1582}
1583
1584
1585# ifdef DEAL_II_DELETED_MOVE_CONSTRUCTOR_BUG
1586template <int rank_, int dim, typename Number>
1589{
1590 for (unsigned int i = 0; i < dim; ++i)
1591 values[i] = other.values[i];
1592 return *this;
1593}
1594
1595
1596
1597template <int rank_, int dim, typename Number>
1600 Tensor<rank_, dim, Number> &&other) noexcept
1601{
1602 for (unsigned int i = 0; i < dim; ++i)
1603 values[i] = other.values[i];
1604 return *this;
1605}
1606# endif
1607
1608
1609template <int rank_, int dim, typename Number>
1610template <typename OtherNumber>
1611constexpr inline bool
1613 const Tensor<rank_, dim, OtherNumber> &p) const
1614{
1615# ifdef DEAL_II_ADOLC_WITH_ADVANCED_BRANCHING
1616 Assert(!(std::is_same_v<Number, adouble> ||
1617 std::is_same_v<OtherNumber, adouble>),
1618 ExcMessage(
1619 "The Tensor equality operator for ADOL-C taped numbers has not yet "
1620 "been extended to support advanced branching."));
1621# endif
1622
1623 for (unsigned int i = 0; i < dim; ++i)
1624 if (numbers::values_are_not_equal(values[i], p.values[i]))
1625 return false;
1626 return true;
1627}
1628
1629
1630// At some places in the library, we have Point<0> for formal reasons
1631// (e.g., we sometimes have Quadrature<dim-1> for faces, so we have
1632// Quadrature<0> for dim=1, and then we have Point<0>). To avoid warnings
1633// in the above function that the loop end check always fails, we
1634// implement this function here
1635template <>
1636template <>
1637constexpr inline bool
1639{
1640 return true;
1641}
1642
1643
1644template <int rank_, int dim, typename Number>
1645template <typename OtherNumber>
1646constexpr bool
1648 const Tensor<rank_, dim, OtherNumber> &p) const
1649{
1650 return !((*this) == p);
1651}
1652
1653
1654template <int rank_, int dim, typename Number>
1655template <typename OtherNumber>
1656constexpr inline DEAL_II_ALWAYS_INLINE
1660{
1661 for (unsigned int i = 0; i < dim; ++i)
1662 values[i] += p.values[i];
1663 return *this;
1664}
1665
1666
1667template <int rank_, int dim, typename Number>
1668template <typename OtherNumber>
1669constexpr inline DEAL_II_ALWAYS_INLINE
1673{
1674 for (unsigned int i = 0; i < dim; ++i)
1675 values[i] -= p.values[i];
1676 return *this;
1677}
1678
1679
1680template <int rank_, int dim, typename Number>
1681template <typename OtherNumber>
1682constexpr inline DEAL_II_ALWAYS_INLINE
1684 Tensor<rank_, dim, Number>::operator*=(const OtherNumber &s)
1685{
1686 for (unsigned int i = 0; i < dim; ++i)
1687 values[i] *= s;
1688 return *this;
1689}
1690
1691
1692
1693template <int rank_, int dim, typename Number>
1694template <typename OtherNumber>
1695constexpr inline DEAL_II_ALWAYS_INLINE
1697 Tensor<rank_, dim, Number>::operator/=(const OtherNumber &s)
1698{
1699 if constexpr (std::is_integral<
1700 typename ProductType<Number, OtherNumber>::type>::value ||
1701 std::is_same_v<Number, Differentiation::SD::Expression>)
1702 {
1703 // recurse over the base objects
1704 for (unsigned int d = 0; d < dim; ++d)
1705 values[d] /= s;
1706 }
1707 else
1708 {
1709 // If we can, avoid division by multiplying by the inverse of the given
1710 // factor:
1711 const Number inverse_factor = Number(1.) / s;
1712 for (unsigned int d = 0; d < dim; ++d)
1713 values[d] *= inverse_factor;
1714 }
1715
1716 return *this;
1717}
1718
1719
1720template <int rank_, int dim, typename Number>
1721constexpr inline DEAL_II_ALWAYS_INLINE
1724{
1726
1727 for (unsigned int i = 0; i < dim; ++i)
1728 tmp.values[i] = -values[i];
1729
1730 return tmp;
1731}
1732
1733
1734template <int rank_, int dim, typename Number>
1737{
1738 // Handle cases of a tensor consisting of just one number more
1739 // efficiently:
1740 if constexpr ((rank_ == 1) && (dim == 1) && std::is_arithmetic_v<Number>)
1741 {
1742 return std::abs(values[0]);
1743 }
1744 else if constexpr ((rank_ == 2) && (dim == 1) && std::is_arithmetic_v<Number>)
1745 {
1746 return std::abs(values[0][0]);
1747 }
1748 else
1749 {
1750 // Otherwise fall back to the naive algorithm of taking the square root of
1751 // the sum of squares.
1752
1753 // Make things work with AD types by letting the compiler look up
1754 // the symbol sqrt in namespace std and in the type-associated
1755 // namespaces
1756 using std::sqrt;
1757 return sqrt(norm_square());
1758 }
1759}
1760
1761
1762template <int rank_, int dim, typename Number>
1766{
1767 if constexpr (dim == 0)
1768 return internal::NumberType<
1769 typename numbers::NumberTraits<Number>::real_type>::value(0.0);
1770 else if constexpr (rank_ == 1)
1771 {
1772 // For rank-1 tensors, the square of the norm is simply the sum of
1773 // squares of the elements:
1776 for (unsigned int i = 1; i < dim; ++i)
1778
1779 return s;
1780 }
1781 else
1782 {
1783 // For higher-rank tensors, the square of the norm is the sum
1784 // of squares of sub-tensors
1786 values[0].norm_square();
1787 for (unsigned int i = 1; i < dim; ++i)
1788 s += values[i].norm_square();
1789
1790 return s;
1791 }
1792}
1793
1794
1795
1796template <int rank_, int dim, typename Number>
1797template <class Iterator>
1798inline void
1799Tensor<rank_, dim, Number>::unroll(const Iterator begin,
1800 const Iterator end) const
1801{
1802 if constexpr (rank_ > 1)
1803 {
1804 // For higher-rank tensors, we recurse to the sub-tensors:
1805 Iterator next = begin;
1806 for (unsigned int i = 0; i < dim; ++i)
1807 {
1808 values[i].unroll(next, end);
1809 std::advance(
1811 }
1812 }
1813 else
1814 {
1815 // For rank-1 tensors, we can simply copy the current elements from
1816 // our linear array into the output range:
1817 (void)end;
1818 Assert(std::distance(begin, end) >= dim,
1819 ExcMessage(
1820 "The provided iterator range must contain at least 'dim' "
1821 "elements."));
1822 std::copy(std::begin(values), std::end(values), begin);
1823 }
1824}
1825
1826
1827
1828template <int rank_, int dim, typename Number>
1829constexpr inline unsigned int
1831 const TableIndices<rank_> &indices)
1832{
1833 unsigned int index = 0;
1834 for (int r = 0; r < rank_; ++r)
1835 index = index * dim + indices[r];
1836
1837 return index;
1838}
1839
1840
1841
1842template <int rank_, int dim, typename Number>
1843constexpr inline TableIndices<rank_>
1845{
1846 // Work-around nvcc warning
1847 unsigned int dummy = n_independent_components;
1848 AssertIndexRange(i, dummy);
1849 (void)dummy;
1850
1851 if constexpr (dim == 0)
1852 {
1853 Assert(false,
1854 ExcMessage(
1855 "A tensor with dimension 0 does not store any elements. "
1856 "There is no indexing that can address its elements."));
1857 return {};
1858 }
1859 else
1860 {
1861 TableIndices<rank_> indices;
1862
1863 unsigned int remainder = i;
1864 for (int r = rank_ - 1; r >= 0; --r)
1865 {
1866 indices[r] = remainder % dim;
1867 remainder = remainder / dim;
1868 }
1869 Assert(remainder == 0, ExcInternalError());
1870
1871 return indices;
1872 }
1873}
1874
1875
1876template <int rank_, int dim, typename Number>
1877constexpr inline void
1879{
1880 for (unsigned int i = 0; i < dim; ++i)
1881 values[i] = internal::NumberType<Number>::value(0.0);
1882}
1883
1884
1885template <int rank_, int dim, typename Number>
1886constexpr std::size_t
1888{
1889 return sizeof(Tensor<rank_, dim, Number>);
1890}
1891
1892
1893template <int rank_, int dim, typename Number>
1894template <class Archive>
1895inline void
1896Tensor<rank_, dim, Number>::serialize(Archive &ar, const unsigned int)
1897{
1898 if constexpr (rank_ > 1)
1899 ar &values;
1900 else
1901 ar &boost::serialization::make_array(&values[0], dim);
1902}
1903
1904
1905template <int rank_, int dim, typename Number>
1907
1908#endif // DOXYGEN
1909
1910/* ----------------- Non-member functions operating on tensors. ------------ */
1911
1924template <int rank_, int dim, typename Number>
1925inline std::ostream &
1926operator<<(std::ostream &out, const Tensor<rank_, dim, Number> &p)
1927{
1928 for (unsigned int i = 0; i < dim; ++i)
1929 {
1930 out << p[i];
1931 if (i != dim - 1)
1932 for (unsigned int j = 0; j < rank_; ++j)
1933 out << ' ';
1934 }
1935
1936 return out;
1937}
1938
1939
1946template <int dim, typename Number>
1947inline std::ostream &
1948operator<<(std::ostream &out, const Tensor<0, dim, Number> &p)
1949{
1950 out << static_cast<const Number &>(p);
1951 return out;
1952}
1953
1954
1973template <int dim, typename Number, typename Other>
1976 operator*(const Other &object, const Tensor<0, dim, Number> &t)
1977{
1978 return object * static_cast<const Number &>(t);
1979}
1980
1981
1982
1993template <int dim, typename Number, typename Other>
1996 operator*(const Tensor<0, dim, Number> &t, const Other &object)
1997{
1998 return static_cast<const Number &>(t) * object;
1999}
2000
2001
2013template <int dim, typename Number, typename OtherNumber>
2017 const Tensor<0, dim, OtherNumber> &src2)
2018{
2019 return static_cast<const Number &>(src1) *
2020 static_cast<const OtherNumber &>(src2);
2021}
2022
2023
2031template <int dim, typename Number, typename OtherNumber>
2033 Tensor<0,
2034 dim,
2035 typename ProductType<Number,
2036 typename EnableIfScalar<OtherNumber>::type>::type>
2037 operator/(const Tensor<0, dim, Number> &t, const OtherNumber &factor)
2038{
2039 return static_cast<const Number &>(t) / factor;
2040}
2041
2042
2050template <int dim, typename Number, typename OtherNumber>
2055{
2056 return static_cast<const Number &>(p) + static_cast<const OtherNumber &>(q);
2057}
2058
2059
2067template <int dim, typename Number, typename OtherNumber>
2072{
2073 return static_cast<const Number &>(p) - static_cast<const OtherNumber &>(q);
2074}
2075
2076
2089template <int rank, int dim, typename Number, typename OtherNumber>
2091 Tensor<rank,
2092 dim,
2093 typename ProductType<Number,
2094 typename EnableIfScalar<OtherNumber>::type>::type>
2095 operator*(const Tensor<rank, dim, Number> &t, const OtherNumber &factor)
2096{
2098 tt *= factor;
2099 return tt;
2100}
2101
2102
2115template <int rank, int dim, typename Number, typename OtherNumber>
2117 Tensor<rank,
2118 dim,
2120 OtherNumber>::type>
2121 operator*(const Number &factor, const Tensor<rank, dim, OtherNumber> &t)
2122{
2123 // simply forward to the operator above
2124 return t * factor;
2125}
2126
2127
2128
2138template <int rank, int dim, typename Number, typename OtherNumber>
2140 Tensor<rank,
2141 dim,
2142 typename ProductType<Number,
2143 typename EnableIfScalar<OtherNumber>::type>::type>
2144 operator/(const Tensor<rank, dim, Number> &t, const OtherNumber &factor)
2145{
2147 tt /= factor;
2148 return tt;
2149}
2150
2151
2161template <int rank, int dim, typename Number, typename OtherNumber>
2171
2172
2182template <int rank, int dim, typename Number, typename OtherNumber>
2192
2199template <int dim, typename Number, typename OtherNumber>
2200inline constexpr DEAL_II_ALWAYS_INLINE
2203 const Tensor<0, dim, OtherNumber> &src2)
2204{
2206
2207 tmp *= src2;
2208
2209 return tmp;
2210}
2211
2228template <int rank, int dim, typename Number, typename OtherNumber>
2229inline constexpr DEAL_II_ALWAYS_INLINE
2233{
2235
2236 for (unsigned int i = 0; i < dim; ++i)
2239
2240 return tmp;
2241}
2242
2287template <int rank_1,
2288 int rank_2,
2289 int dim,
2290 typename Number,
2291 typename OtherNumber,
2292 typename = std::enable_if_t<rank_1 >= 1 && rank_2 >= 1>>
2293constexpr inline DEAL_II_ALWAYS_INLINE
2294 typename Tensor<rank_1 + rank_2 - 2,
2295 dim,
2296 typename ProductType<Number, OtherNumber>::type>::tensor_type
2299{
2300 // Treat some common cases separately. Specifically, these are the dot
2301 // product between two rank-1 tensors, and the product between a
2302 // rank-2 tensor and a rank-1 tensor. Both of these lead to a linear
2303 // loop over adjacent memory and can be dealt with efficiently; in the
2304 // latter case (rank-2 times rank-1), we implement things by deferring
2305 // to rank-1 times rank-1 dot products.
2306 if constexpr ((rank_1 == 1) && (rank_2 == 1))
2307 {
2308 // This is a dot product between two rank-1 tensors. Write it out as
2309 // a linear loop:
2310 static_assert(dim > 0, "Tensors cannot have dimension zero.");
2311 typename ProductType<Number, OtherNumber>::type sum = src1[0] * src2[0];
2312 for (unsigned int i = 1; i < dim; ++i)
2313 sum += src1[i] * src2[i];
2314
2315 return sum;
2316 }
2317 else if constexpr ((rank_1 == 2) && (rank_2 == 1))
2318 {
2319 // This is a product between a rank-2 and a rank-1 tensor. This
2320 // corresponds to taking dot products between the rows of the former
2321 // and the latter.
2322 typename Tensor<
2323 rank_1 + rank_2 - 2,
2324 dim,
2325 typename ProductType<Number, OtherNumber>::type>::tensor_type result;
2326 for (unsigned int i = 0; i < dim; ++i)
2327 result[i] += src1[i] * src2;
2328
2329 return result;
2330 }
2331 else
2332 {
2333 // Treat all of the other cases using the more general contraction
2334 // machinery.
2335 typename Tensor<
2336 rank_1 + rank_2 - 2,
2337 dim,
2338 typename ProductType<Number, OtherNumber>::type>::tensor_type result{};
2339
2340 TensorAccessors::internal::
2341 ReorderedIndexView<0, rank_2, const Tensor<rank_2, dim, OtherNumber>>
2342 reordered = TensorAccessors::reordered_index_view<0, rank_2>(src2);
2343 TensorAccessors::contract<1, rank_1, rank_2, dim>(result,
2344 src1,
2345 reordered);
2346
2347 return result;
2348 }
2349}
2350
2351
2380template <int index_1,
2381 int index_2,
2382 int rank_1,
2383 int rank_2,
2384 int dim,
2385 typename Number,
2386 typename OtherNumber>
2387constexpr inline DEAL_II_ALWAYS_INLINE
2388 typename Tensor<rank_1 + rank_2 - 2,
2389 dim,
2390 typename ProductType<Number, OtherNumber>::type>::tensor_type
2393{
2394 Assert(0 <= index_1 && index_1 < rank_1,
2395 ExcMessage(
2396 "The specified index_1 must lie within the range [0,rank_1)"));
2397 Assert(0 <= index_2 && index_2 < rank_2,
2398 ExcMessage(
2399 "The specified index_2 must lie within the range [0,rank_2)"));
2400
2401 using namespace TensorAccessors;
2402 using namespace TensorAccessors::internal;
2403
2404 // Reorder index_1 to the end of src1:
2406 reord_01 = reordered_index_view<index_1, rank_1>(src1);
2407
2408 // Reorder index_2 to the end of src2:
2409 const ReorderedIndexView<index_2,
2410 rank_2,
2412 reord_02 = reordered_index_view<index_2, rank_2>(src2);
2413
2414 typename Tensor<rank_1 + rank_2 - 2,
2415 dim,
2416 typename ProductType<Number, OtherNumber>::type>::tensor_type
2417 result{};
2418 TensorAccessors::contract<1, rank_1, rank_2, dim>(result, reord_01, reord_02);
2419 return result;
2420}
2421
2422
2453template <int index_1,
2454 int index_2,
2455 int index_3,
2456 int index_4,
2457 int rank_1,
2458 int rank_2,
2459 int dim,
2460 typename Number,
2461 typename OtherNumber>
2462constexpr inline
2463 typename Tensor<rank_1 + rank_2 - 4,
2464 dim,
2465 typename ProductType<Number, OtherNumber>::type>::tensor_type
2466 double_contract(const Tensor<rank_1, dim, Number> &src1,
2468{
2469 Assert(0 <= index_1 && index_1 < rank_1,
2470 ExcMessage(
2471 "The specified index_1 must lie within the range [0,rank_1)"));
2472 Assert(0 <= index_3 && index_3 < rank_1,
2473 ExcMessage(
2474 "The specified index_3 must lie within the range [0,rank_1)"));
2475 Assert(index_1 != index_3,
2476 ExcMessage("index_1 and index_3 must not be the same"));
2477 Assert(0 <= index_2 && index_2 < rank_2,
2478 ExcMessage(
2479 "The specified index_2 must lie within the range [0,rank_2)"));
2480 Assert(0 <= index_4 && index_4 < rank_2,
2481 ExcMessage(
2482 "The specified index_4 must lie within the range [0,rank_2)"));
2483 Assert(index_2 != index_4,
2484 ExcMessage("index_2 and index_4 must not be the same"));
2485
2486 using namespace TensorAccessors;
2487 using namespace TensorAccessors::internal;
2488
2489 // Reorder index_1 to the end of src1:
2491 reord_1 = TensorAccessors::reordered_index_view<index_1, rank_1>(src1);
2492
2493 // Reorder index_2 to the end of src2:
2495 reord_2 = TensorAccessors::reordered_index_view<index_2, rank_2>(src2);
2496
2497 // Now, reorder index_3 to the end of src1. We have to make sure to
2498 // preserve the original ordering: index_1 has been removed. If
2499 // index_3 > index_1, we have to use (index_3 - 1) instead:
2501 (index_3 < index_1 ? index_3 : index_3 - 1),
2502 rank_1,
2503 ReorderedIndexView<index_1, rank_1, const Tensor<rank_1, dim, Number>>>
2504 reord_3 =
2505 TensorAccessors::reordered_index_view < index_3 < index_1 ? index_3 :
2506 index_3 - 1,
2507 rank_1 > (reord_1);
2508
2509 // Now, reorder index_4 to the end of src2. We have to make sure to
2510 // preserve the original ordering: index_2 has been removed. If
2511 // index_4 > index_2, we have to use (index_4 - 1) instead:
2513 (index_4 < index_2 ? index_4 : index_4 - 1),
2514 rank_2,
2516 reord_4 =
2517 TensorAccessors::reordered_index_view < index_4 < index_2 ? index_4 :
2518 index_4 - 1,
2519 rank_2 > (reord_2);
2520
2521 typename Tensor<rank_1 + rank_2 - 4,
2522 dim,
2523 typename ProductType<Number, OtherNumber>::type>::tensor_type
2524 result{};
2525 TensorAccessors::contract<2, rank_1, rank_2, dim>(result, reord_3, reord_4);
2526 return result;
2527}
2528
2529
2542template <int rank, int dim, typename Number, typename OtherNumber>
2543constexpr inline DEAL_II_ALWAYS_INLINE
2545 scalar_product(const Tensor<rank, dim, Number> &left,
2546 const Tensor<rank, dim, OtherNumber> &right)
2547{
2549 TensorAccessors::contract<rank, rank, rank, dim>(result, left, right);
2550 return result;
2551}
2552
2553
2571template <template <int, int, typename> class TensorT1,
2572 template <int, int, typename>
2573 class TensorT2,
2574 template <int, int, typename>
2575 class TensorT3,
2576 int rank_1,
2577 int rank_2,
2578 int dim,
2579 typename T1,
2580 typename T2,
2581 typename T3>
2582constexpr inline DEAL_II_ALWAYS_INLINE
2584 contract3(const TensorT1<rank_1, dim, T1> &left,
2585 const TensorT2<rank_1 + rank_2, dim, T2> &middle,
2586 const TensorT3<rank_2, dim, T3> &right)
2587{
2588 using return_type =
2590 return TensorAccessors::contract3<rank_1, rank_2, dim, return_type>(left,
2591 middle,
2592 right);
2593}
2594
2595
2606template <int rank_1,
2607 int rank_2,
2608 int dim,
2609 typename Number,
2610 typename OtherNumber>
2611constexpr inline DEAL_II_ALWAYS_INLINE
2615{
2616 typename Tensor<rank_1 + rank_2,
2617 dim,
2618 typename ProductType<Number, OtherNumber>::type>::tensor_type
2619 result{};
2620 TensorAccessors::contract<0, rank_1, rank_2, dim>(result, src1, src2);
2621 return result;
2622}
2623
2624
2643template <int dim, typename Number>
2645cross_product_2d(const Tensor<1, dim, Number> &src)
2646{
2647 Assert(dim == 2, ExcInternalError());
2648
2650
2651 result[0] = src[1];
2652 result[1] = -src[0];
2653
2654 return result;
2655}
2656
2657
2667template <int dim, typename Number1, typename Number2>
2668constexpr inline DEAL_II_ALWAYS_INLINE
2670 cross_product_3d(const Tensor<1, dim, Number1> &src1,
2671 const Tensor<1, dim, Number2> &src2)
2672{
2673 Assert(dim == 3, ExcInternalError());
2674
2676
2677 // avoid compiler warnings
2678 constexpr int s0 = 0 % dim;
2679 constexpr int s1 = 1 % dim;
2680 constexpr int s2 = 2 % dim;
2681
2682 result[s0] = src1[s1] * src2[s2] - src1[s2] * src2[s1];
2683 result[s1] = src1[s2] * src2[s0] - src1[s0] * src2[s2];
2684 result[s2] = src1[s0] * src2[s1] - src1[s1] * src2[s0];
2685
2686 return result;
2687}
2688
2689
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>
2911adjugate(const Tensor<2, dim, Number> &t)
2912{
2913 return determinant(t) * invert(t);
2914}
2915
2916
2930template <int dim, typename Number>
2931constexpr Tensor<2, dim, Number>
2932cofactor(const Tensor<2, dim, Number> &t)
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 {
3020 Number sum = internal::NumberType<Number>::value(0.0);
3021 for (unsigned int i = 0; i < dim; ++i)
3022 sum += numbers::NumberTraits<Number>::abs(t[i][j]);
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 {
3046 Number sum = internal::NumberType<Number>::value(0.0);
3047 for (unsigned int j = 0; j < dim; ++j)
3048 sum += numbers::NumberTraits<Number>::abs(t[i][j]);
3049
3050 if (sum > max)
3051 max = sum;
3052 }
3053
3054 return max;
3055}
3056
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:684
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:137
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:2144
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, typename EnableIfScalar< OtherNumber >::type >::type > operator/(const Tensor< 0, dim, Number > &t, const OtherNumber &factor)
Definition tensor.h:2037
Number * begin_raw()
static constexpr unsigned int rank
Definition tensor.h:490
constexpr Tensor(const Tensor< rank_, dim, OtherNumber > &initializer)
std::conditional_t< rank_==1, Number, Tensor< rank_ - 1, dim, Number > > value_type
Definition tensor.h:515
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:2016
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:531
constexpr bool operator!=(const Tensor< rank_, dim, OtherNumber > &) const
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:2202
constexpr value_type & operator[](const unsigned int i)
Number * end_raw()
constexpr DEAL_II_HOST_DEVICE_ALWAYS_INLINE Tensor< 0, dim, typename ProductType< Number, OtherNumber >::type > operator-(const Tensor< 0, dim, Number > &p, const Tensor< 0, dim, OtherNumber > &q)
Definition tensor.h:2070
friend class Tensor
Definition tensor.h:868
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:2164
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:1976
constexpr DEAL_II_HOST_DEVICE_ALWAYS_INLINE Tensor()
Number l1_norm(const Tensor< 2, dim, Number > &t)
Definition tensor.h:3015
static constexpr unsigned int dimension
Definition tensor.h:485
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:2121
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:854
constexpr Tensor & operator+=(const Tensor< rank_, dim, OtherNumber > &)
constexpr DEAL_II_HOST_DEVICE_ALWAYS_INLINE Tensor< 0, dim, typename ProductType< Number, OtherNumber >::type > operator+(const Tensor< 0, dim, Number > &p, const Tensor< 0, dim, OtherNumber > &q)
Definition tensor.h:2053
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:2231
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:2185
constexpr ProductType< Number, Other >::type operator*(const Tensor< 0, dim, Number > &t, const Other &object)
Definition tensor.h:1996
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:2095
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:506
constexpr Tensor operator-() const
constexpr Tensor & operator=(const Tensor< rank_, dim, OtherNumber > &rhs)
#define DEAL_II_ALWAYS_INLINE
Definition config.h:109
#define DEAL_II_DEPRECATED
Definition config.h:207
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:500
#define DEAL_II_CXX20_REQUIRES(condition)
Definition config.h:177
#define DEAL_II_CXX23_ASSUME(expr)
Definition config.h:194
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:501
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)
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
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:902
constexpr bool value_is_zero(const Number &value)
Definition numbers.h:910
constexpr bool values_are_equal(const Number1 &value_1, const Number2 &value_2)
Definition numbers.h:894
STL namespace.
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
#define DEAL_II_HOST_DEVICE
Definition numbers.h:30
#define DEAL_II_HOST_DEVICE_ALWAYS_INLINE
Definition numbers.h:31
typename internal::ProductTypeImpl< std::decay_t< T >, std::decay_t< U > >::type type
static constexpr DEAL_II_HOST_DEVICE_ALWAYS_INLINE const T & value(const T &t)
Definition numbers.h:697
decltype(std::declval< T >() *std::declval< U >()) type
static real_type abs(const number &x)
Definition numbers.h:588
static constexpr real_type abs_square(const number &x)
Definition numbers.h:579
DEAL_II_HOST constexpr Number determinant(const SymmetricTensor< 2, dim, Number > &)
DEAL_II_HOST constexpr SymmetricTensor< 2, dim, Number > invert(const SymmetricTensor< 2, dim, Number > &)
DEAL_II_HOST constexpr SymmetricTensor< 4, dim, Number > outer_product(const SymmetricTensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, Number > &t2)
DEAL_II_HOST constexpr Number trace(const SymmetricTensor< 2, dim2, Number > &)
Tensor< 2, dim, Number > project_onto_orthogonal_tensors(const Tensor< 2, dim, Number > &A)
Definition tensor.cc:81
std::ostream & operator<<(std::ostream &out, const Tensor< rank_, dim, Number > &p)
Definition tensor.h:1926
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:2202
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:1976
Number l1_norm(const Tensor< 2, dim, Number > &t)
Definition tensor.h:3015