30template <
typename T,
int... n>
36template <
typename T >
40 static constexpr int ndim = 1;
41 static constexpr int first_dim = 0;
43 MFEM_HOST_DEVICE
const T&
operator[](
int )
const {
return values; }
45 MFEM_HOST_DEVICE
const T&
operator()(
int )
const {
return values; }
46 MFEM_HOST_DEVICE
operator T()
const {
return values; }
50template <
typename T,
int n0 >
54 static constexpr int ndim = 1;
55 static constexpr int first_dim = n0;
56 MFEM_HOST_DEVICE T&
operator[](
int i) {
return values[i]; }
57 MFEM_HOST_DEVICE
const T&
operator[](
int i)
const {
return values[i]; }
58 MFEM_HOST_DEVICE T&
operator()(
int i) {
return values[i]; }
59 MFEM_HOST_DEVICE
const T&
operator()(
int i)
const {
return values[i]; }
63template <
typename T >
67 static constexpr int ndim = 1;
68 static constexpr int first_dim = 0;
70 MFEM_HOST_DEVICE
const T&
operator[](
int )
const {
return values; }
72 MFEM_HOST_DEVICE
const T&
operator()(
int )
const {
return values; }
76template <
typename T,
int n0,
int n1 >
80 static constexpr int ndim = 2;
81 static constexpr int first_dim = n0;
86 MFEM_HOST_DEVICE T&
operator()(
int i,
int j) {
return values[i][j]; }
87 MFEM_HOST_DEVICE
const T&
operator()(
int i,
int j)
const {
return values[i][j]; }
88 tensor < T, n1 > values[n0];
91template <
typename T,
int n1 >
95 static constexpr int ndim = 2;
96 static constexpr int first_dim = 0;
101 MFEM_HOST_DEVICE T&
operator()(
int ,
int j) {
return values[j]; }
102 MFEM_HOST_DEVICE
const T&
operator()(
int ,
int j)
const {
return values[j]; }
106template <
typename T,
int n0,
int n1,
int n2 >
110 static constexpr int ndim = 3;
111 static constexpr int first_dim = n0;
118 MFEM_HOST_DEVICE T&
operator()(
int i,
int j,
int k) {
return values[i][j][k]; }
119 MFEM_HOST_DEVICE
const T&
operator()(
int i,
int j,
int k)
const {
return values[i][j][k]; }
120 tensor < T, n1, n2 > values[n0];
123template <
typename T,
int n0,
int n1,
int n2,
int n3 >
127 static constexpr int ndim = 4;
128 static constexpr int first_dim = n0;
137 MFEM_HOST_DEVICE T&
operator()(
int i,
int j,
int k,
int l) {
return values[i][j][k][l]; }
138 MFEM_HOST_DEVICE
const T&
operator()(
int i,
int j,
int k,
int l)
const {
return values[i][j][k][l]; }
139 tensor < T, n1, n2, n3 > values[n0];
142template <
typename T,
int n0,
int n1,
int n2,
int n3,
int n4 >
146 static constexpr int ndim = 5;
147 static constexpr int first_dim = n0;
154 int j)
const {
return values[i][j]; }
157 int k)
const {
return values[i][j][k]; }
160 int l)
const {
return values[i][j][k][l]; }
161 MFEM_HOST_DEVICE T&
operator()(
int i,
int j,
int k,
int l,
int m) {
return values[i][j][k][l][m]; }
162 MFEM_HOST_DEVICE
const T&
operator()(
int i,
int j,
int k,
int l,
int m)
const {
return values[i][j][k][l][m]; }
163 tensor < T, n1, n2, n3, n4 > values[n0];
172 MFEM_HOST_DEVICE
operator real_t() {
return 0.0; }
175 template <
typename T,
int... n>
176 MFEM_HOST_DEVICE
operator tensor<T, n...>()
178 return tensor<T, n...> {};
182 template <
typename... T>
189 template <
typename T>
307template <
typename T,
int n1,
int n2 = 1>
309 (n1 == 1 && n2 == 1), T,
326template <
typename lambda_type>
344template <
int n1,
typename lambda_type>
346tensor<
decltype(
f(n1)), n1>
348 using T =
decltype(
f(n1));
350 for (
int i = 0; i < n1; i++)
369template <
int n1,
int n2,
typename lambda_type>
371tensor<
decltype(
f(n1, n2)), n1, n2>
373 using T =
decltype(
f(n1, n2));
375 for (
int i = 0; i < n1; i++)
377 for (
int j = 0; j < n2; j++)
398template <
int n1,
int n2,
int n3,
typename lambda_type>
400tensor<
decltype(
f(n1, n2, n3)), n1, n2, n3>
402 using T =
decltype(
f(n1, n2, n3));
404 for (
int i = 0; i < n1; i++)
406 for (
int j = 0; j < n2; j++)
408 for (
int k = 0; k < n3; k++)
410 A(i, j, k) =
f(i, j, k);
431template <
int n1,
int n2,
int n3,
int n4,
typename lambda_type>
433tensor<
decltype(
f(n1, n2, n3, n4)), n1, n2, n3, n4>
435 using T =
decltype(
f(n1, n2, n3, n4));
437 for (
int i = 0; i < n1; i++)
439 for (
int j = 0; j < n2; j++)
441 for (
int k = 0; k < n3; k++)
443 for (
int l = 0; l < n4; l++)
445 A(i, j, k, l) =
f(i, j, k, l);
454template <
typename T,
int m,
int n> MFEM_HOST_DEVICE
464template <
typename T> MFEM_HOST_DEVICE
478template <
typename S,
typename T,
int... n>
481tensor<
decltype(S {} + T{}), n...>
483 tensor<
decltype(S{} + T{}), n...> C{};
484 for (
int i = 0; i < tensor<T, n...>::first_dim; i++)
497template <
typename T,
int... n>
501 for (
int i = 0; i <
tensor<T, n...>::first_dim; i++)
516template <
typename S,
typename T,
int... n>
519tensor<
decltype(S {} + T{}), n...>
521 tensor<
decltype(S{} + T{}), n...> C{};
522 for (
int i = 0; i < tensor<T, n...>::first_dim; i++)
537template <
typename S,
typename T,
int... n,
538 typename =
typename std::enable_if<std::is_arithmetic<S>::value ||
539 is_dual_number<S>::value>::type>
541tensor<
decltype(S {} * T{}), n...>
543 tensor<
decltype(S{} * T{}), n...> C{};
544 for (
int i = 0; i < tensor<T, n...>::first_dim; i++)
559template <
typename S,
typename T,
int... n,
560 typename =
typename std::enable_if<std::is_arithmetic<S>::value ||
561 is_dual_number<S>::value>::type>
563tensor<
decltype(T {} * S{}), n...>
565 tensor<
decltype(T{} * S{}), n...> C{};
566 for (
int i = 0; i < tensor<T, n...>::first_dim; i++)
581template <
typename S,
typename T,
int... n,
582 typename =
typename std::enable_if<std::is_arithmetic<S>::value ||
583 is_dual_number<S>::value>::type>
585tensor<
decltype(S {} * T{}), n...>
587 tensor<
decltype(S{} * T{}), n...> C{};
588 for (
int i = 0; i < tensor<T, n...>::first_dim; i++)
603template <
typename S,
typename T,
int... n,
604 typename =
typename std::enable_if<std::is_arithmetic<S>::value ||
605 is_dual_number<S>::value>::type>
607tensor<
decltype(T {} * S{}), n...>
609 tensor<
decltype(T{} * S{}), n...> C{};
610 for (
int i = 0; i < tensor<T, n...>::first_dim; i++)
625template <
typename S,
typename T,
int... n> MFEM_HOST_DEVICE
629 for (
int i = 0; i <
tensor<S, n...>::first_dim; i++)
642template <
typename T> MFEM_HOST_DEVICE
645 return A.values += B;
654template <
typename T> MFEM_HOST_DEVICE
657 return A.values += B;
666template <
typename T> MFEM_HOST_DEVICE
669 return A.values += B;
678template <
typename T,
int... n> MFEM_HOST_DEVICE
692template <
typename S,
typename T,
int... n> MFEM_HOST_DEVICE
695 for (
int i = 0; i <
tensor<S, n...>::first_dim; i++)
708template <
typename T,
int... n> MFEM_HOST_DEVICE
723template <
typename S,
typename T> MFEM_HOST_DEVICE
724auto outer(S A, T B) ->
decltype(A * B)
726 static_assert(std::is_arithmetic<S>::value && std::is_arithmetic<T>::value,
727 "outer product types must be tensor or arithmetic_type");
731template <
typename T,
int n,
int m> MFEM_HOST_DEVICE
735 for (
int i = 0; i < n; i++)
737 for (
int j = 0; j < m; j++)
739 B(i + j * m) = A(i, j);
749template <
typename S,
typename T,
int n> MFEM_HOST_DEVICE
750tensor<
decltype(S{} * T{}), n> outer(S A, tensor<T, n> B)
752 static_assert(std::is_arithmetic<S>::value,
753 "outer product types must be tensor or arithmetic_type");
754 tensor<
decltype(S{} * T{}), n> AB{};
755 for (
int i = 0; i < n; i++)
766template <
typename S,
typename T,
int m> MFEM_HOST_DEVICE
767tensor<
decltype(S{} * T{}), m> outer(
const tensor<S, m>& A, T B)
769 static_assert(std::is_arithmetic<T>::value,
770 "outer product types must be tensor or arithmetic_type");
771 tensor<
decltype(S{} * T{}), m> AB{};
772 for (
int i = 0; i < m; i++)
783template <
typename T,
int n> MFEM_HOST_DEVICE
793template <
typename T,
int n> MFEM_HOST_DEVICE
804template <
typename S,
typename T,
int m,
int n> MFEM_HOST_DEVICE
805tensor<
decltype(S{} * T{}), m, n> outer(S A,
const tensor<T, m, n>& B)
807 static_assert(std::is_arithmetic<S>::value,
808 "outer product types must be tensor or arithmetic_type");
809 tensor<
decltype(S{} * T{}), m, n> AB{};
810 for (
int i = 0; i < m; i++)
812 for (
int j = 0; j < n; j++)
814 AB[i][j] = A * B[i][j];
824template <
typename S,
typename T,
int m,
int n> MFEM_HOST_DEVICE
825tensor<
decltype(S{} * T{}), m, n> outer(
const tensor<S, m>& A,
826 const tensor<T, n>& B)
828 tensor<
decltype(S{} * T{}), m, n> AB{};
829 for (
int i = 0; i < m; i++)
831 for (
int j = 0; j < n; j++)
833 AB[i][j] = A[i] * B[j];
844template <
typename S,
typename T,
int m,
int n> MFEM_HOST_DEVICE
845tensor<
decltype(S{} * T{}), m, n> outer(
const tensor<S, m, n>& A, T B)
847 static_assert(std::is_arithmetic<T>::value,
848 "outer product types must be tensor or arithmetic_type");
849 tensor<
decltype(S{} * T{}), m, n> AB{};
850 for (
int i = 0; i < m; i++)
852 for (
int j = 0; j < n; j++)
854 AB[i][j] = A[i][j] * B;
865template <
typename S,
typename T,
int m,
int n,
int p> MFEM_HOST_DEVICE
866tensor<
decltype(S{} * T{}), m, n,
p> outer(
const tensor<S, m, n>& A,
867 const tensor<T, p>& B)
869 tensor<
decltype(S{} * T{}), m, n,
p> AB{};
870 for (
int i = 0; i < m; i++)
872 for (
int j = 0; j < n; j++)
874 for (
int k = 0; k <
p; k++)
876 AB[i][j][k] = A[i][j] * B[k];
888template <
typename S,
typename T,
int m,
int n,
int p> MFEM_HOST_DEVICE
889tensor<
decltype(S{} * T{}), m, n,
p> outer(
const tensor<S, m>& A,
890 const tensor<T, n, p>& B)
892 tensor<
decltype(S{} * T{}), m, n,
p> AB{};
893 for (
int i = 0; i < m; i++)
895 for (
int j = 0; j < n; j++)
897 for (
int k = 0; k <
p; k++)
899 AB[i][j][k] = A[i] * B[j][k];
910template <
typename S,
typename T,
int m,
int n,
int p,
int q> MFEM_HOST_DEVICE
911tensor<
decltype(S{} * T{}), m, n,
p, q> outer(
const tensor<S, m, n>& A,
912 const tensor<T, p, q>& B)
914 tensor<
decltype(S{} * T{}), m, n,
p, q> AB{};
915 for (
int i = 0; i < m; i++)
917 for (
int j = 0; j < n; j++)
919 for (
int k = 0; k <
p; k++)
921 for (
int l = 0; l < q; l++)
923 AB[i][j][k][l] = A[i][j] * B[k][l];
940template <
typename S,
typename T,
int m,
int n> MFEM_HOST_DEVICE
944 decltype(S{} * T{}) sum{};
945 for (
int i = 0; i < m; i++)
947 for (
int j = 0; j < n; j++)
949 sum += A[i][j] * B[i][j];
964template <
typename S,
typename T,
int m,
int n,
int p> MFEM_HOST_DEVICE
967tensor<
decltype(S {} * T{}), m,
p>
969 tensor<
decltype(S{} * T{}), m,
p> AB{};
970 for (
int i = 0; i < m; i++)
972 for (
int j = 0; j <
p; j++)
974 for (
int k = 0; k < n; k++)
976 AB[i][j] = AB[i][j] + A[i][k] * B[k][j];
987template <
typename S,
typename T,
int m,
int n> MFEM_HOST_DEVICE
989tensor<
decltype(S {} * T{}), n>
991 tensor<
decltype(S{} * T{}), n> AB{};
992 for (
int i = 0; i < n; i++)
994 for (
int j = 0; j < m; j++)
996 AB[i] = AB[i] + A[j] * B[j][i];
1006template <
typename S,
typename T,
int m,
int n> MFEM_HOST_DEVICE
1008tensor<
decltype(S {} * T{}), m>
1010 tensor<
decltype(S{} * T{}), m> AB{};
1011 for (
int i = 0; i < m; i++)
1013 for (
int j = 0; j < n; j++)
1015 AB[i] = AB[i] + A[i][j] * B[j];
1025template <
typename S,
typename T,
int m,
int n,
int p> MFEM_HOST_DEVICE
1027tensor<
decltype(S {} * T{}), m, n>
1029 tensor<
decltype(S{} * T{}), m, n> AB{};
1030 for (
int i = 0; i < m; i++)
1032 for (
int j = 0; j < n; j++)
1034 for (
int k = 0; k <
p; k++)
1036 AB[i][j] += A[i][j][k] * B[k];
1087template <
typename S,
typename T,
int m> MFEM_HOST_DEVICE
1091 decltype(S{} * T{}) AB{};
1092 for (
int i = 0; i < m; i++)
1099template <
typename T,
int m> MFEM_HOST_DEVICE
1104 for (
int i = 0; i < m; i++)
1111template <
typename S,
typename T,
int m,
int n0,
int n1,
int... n>
1114tensor<
decltype(S {} * T{}), n0, n1, n...>
1116 tensor<
decltype(S{} * T{}), n0, n1, n...> AB{};
1117 for (
int i = 0; i < n0; i++)
1119 for (
int j = 0; j < m; j++)
1121 AB[i] = AB[i] + A[j] * B[j][i];
1131template <
typename S,
typename T,
typename U,
int m,
int n> MFEM_HOST_DEVICE
1134decltype(S {} * T{} * U{})
1136 decltype(S{} * T{} * U{}) uAv{};
1137 for (
int i = 0; i < m; i++)
1139 for (
int j = 0; j < n; j++)
1141 uAv +=
u[i] * A[i][j] * v[j];
1158template <
typename S,
typename T,
int m,
int n,
int p,
int q> MFEM_HOST_DEVICE
1160tensor<
decltype(S {} * T{}), m, n>
1162 tensor<
decltype(S{} * T{}), m, n> AB{};
1163 for (
int i = 0; i < m; i++)
1165 for (
int j = 0; j < n; j++)
1167 for (
int k = 0; k <
p; k++)
1169 for (
int l = 0; l < q; l++)
1171 AB[i][j] += A[i][j][k][l] * B[k][l];
1184template <
typename S,
typename T,
int m,
int n,
int p> MFEM_HOST_DEVICE
1186tensor<
decltype(S {} * T{}), m>
1188 tensor<
decltype(S{} * T{}), m> AB{};
1189 for (
int i = 0; i < m; i++)
1191 for (
int j = 0; j < n; j++)
1193 for (
int k = 0; k <
p; k++)
1195 AB[i] += A[i][j][k] * B[j][k];
1206template <
typename S,
typename T,
int m,
int n> MFEM_HOST_DEVICE
1210 decltype(S{} * T{}) AB{};
1211 for (
int i = 0; i < m; i++)
1213 for (
int j = 0; j < n; j++)
1215 AB += A[i][j] * B[i][j];
1224template <
typename S,
typename T,
int... m,
int... n> MFEM_HOST_DEVICE
1235template <
typename T,
int m> MFEM_HOST_DEVICE
1239 for (
int i = 0; i < m; i++)
1241 total += A[i] * A[i];
1250template <
typename T,
int m,
int n> MFEM_HOST_DEVICE
1254 for (
int i = 0; i < m; i++)
1256 for (
int j = 0; j < n; j++)
1258 total += A[i][j] * A[i][j];
1268template <
typename T,
int... n> MFEM_HOST_DEVICE
1271 return std::sqrt(
sqnorm(A));
1274template <
typename T,
int n,
int m> MFEM_HOST_DEVICE
1277 static_assert((n == m) || ((n == 2) && (m == 1)) || ((n == 3) && (m == 1)) ||
1278 ((n == 3) && (m == 2)),
"unsupported combination of n and m");
1279 if constexpr (n == m)
1283 if constexpr (((n == 2) && (m == 1)) ||
1284 ((n == 3) && (m == 1)))
1288 else if constexpr ((n == 3) && (m == 2))
1290 T E = A[0][0] * A[0][0] + A[1][0] * A[1][0] + A[2][0] * A[2][0];
1291 T G = A[0][1] * A[0][1] + A[1][1] * A[1][1] + A[2][1] * A[2][1];
1292 T F = A[0][0] * A[0][1] + A[1][0] * A[1][1] + A[2][0] * A[2][1];
1293 return std::sqrt(E * G - F * F);
1304template <
typename T,
int... n> MFEM_HOST_DEVICE
1306decltype(A /
norm(A))
1316template <
typename T,
int n> MFEM_HOST_DEVICE
1320 for (
int i = 0; i < n; i++)
1322 trA = trA + A[i][i];
1332template <
typename T,
int n> MFEM_HOST_DEVICE
1336 for (
int i = 0; i < n; i++)
1338 for (
int j = 0; j < n; j++)
1340 symA[i][j] = 0.5 * (A[i][j] + A[j][i]);
1353template <
typename T,
int n> MFEM_HOST_DEVICE
1358 for (
int i = 0; i < n; i++)
1360 devA[i][i] -= trA / n;
1373 for (
int i = 0; i <
dim; i++)
1375 for (
int j = 0; j <
dim; j++)
1387template <
typename T,
int m,
int n> MFEM_HOST_DEVICE
1391 for (
int i = 0; i < n; i++)
1393 for (
int j = 0; j < m; j++)
1405template <
typename T> MFEM_HOST_DEVICE
1411template <
typename T> MFEM_HOST_DEVICE
1414 return A[0][0] * A[1][1] - A[0][1] * A[1][0];
1417template <
typename T> MFEM_HOST_DEVICE
1420 return A[0][0] * A[1][1] * A[2][2] + A[0][1] * A[1][2] * A[2][0] + A[0][2] *
1422 A[0][0] * A[1][2] * A[2][1] - A[0][1] * A[1][0] * A[2][2] - A[0][2] * A[1][1] *
1426template <
typename T> MFEM_HOST_DEVICE
1432template <
typename T> MFEM_HOST_DEVICE
1451 const real_t zeta = (d3 - d0) / (2.0 * d2);
1452 const real_t azeta = fabs(zeta);
1453 if (azeta < std::sqrt(1.0/std::numeric_limits<T>::epsilon()))
1455 t = copysign(1./(azeta + std::sqrt(1. + zeta*zeta)), zeta);
1459 t = copysign(0.5/azeta, zeta);
1461 c = std::sqrt(1./(1. + t*t));
1490template <
typename T> MFEM_HOST_DEVICE
1496 mult = frexp(d_max, &d_exp);
1497 if (d_exp == std::numeric_limits<T>::max_exponent)
1499 mult *= std::numeric_limits<T>::radix;
1509template <
typename T> MFEM_HOST_DEVICE
1518template <
typename T> MFEM_HOST_DEVICE
1529 if (d_max < fabs(d1)) { d_max = fabs(d1); }
1530 if (d_max < fabs(d2)) { d_max = fabs(d2); }
1531 if (d_max < fabs(d3)) { d_max = fabs(d3); }
1540 real_t t = 0.5*((d0+d2)*(d0-d2)+(d1-d3)*(d1+d3));
1541 real_t s = d0*d2 + d1*d3;
1542 s = std::sqrt(0.5*(d0*d0 + d1*d1 + d2*d2 + d3*d3) + std::sqrt(t*t + s*s));
1548 t = fabs(d0*d3 - d1*d2) / s;
1573template <
int n> MFEM_HOST_DEVICE
1576 for (
int i = 0; i < n; ++i)
1578 for (
int j = i + 1; j < n; ++j)
1580 if (std::abs(A(i, j) - A(j, i)) > abs_tolerance)
1597inline MFEM_HOST_DEVICE
1615inline MFEM_HOST_DEVICE
1626 auto subtensor = make_tensor<2, 2>([A](
int i,
int j) {
return A(i, j); });
1640template <
typename T,
int n> MFEM_HOST_DEVICE
1643 auto abs = [](
real_t x) {
return (x < 0) ? -x : x; };
1650 auto swap_scalar = [](T& x, T& y)
1660 for (
int i = 0; i < n; i++)
1666 for (
int j = i + 1; j < n; j++)
1668 if (
abs(A[j][i]) > max_val)
1670 max_val =
abs(A[j][i]);
1675 swap_scalar(
b[max_row],
b[i]);
1676 swap_vector(A[max_row], A[i]);
1679 for (
int j = i + 1; j < n; j++)
1681 real_t c = -A[j][i] / A[i][i];
1689 for (
int i = n - 1; i >= 0; i--)
1691 x[i] =
b[i] / A[i][i];
1692 for (
int j = i - 1; j >= 0; j--)
1694 b[j] -= A[j][i] * x[i];
1706template <
typename T>
1712template <
typename T>
1715 T inv_detA(1.0_r /
det(A));
1719 invA[0][0] = A[1][1] * inv_detA;
1720 invA[0][1] = -A[0][1] * inv_detA;
1721 invA[1][0] = -A[1][0] * inv_detA;
1722 invA[1][1] = A[0][0] * inv_detA;
1731template <
typename T>
1734 T inv_detA(1.0_r /
det(A));
1738 invA[0][0] = (A[1][1] * A[2][2] - A[1][2] * A[2][1]) * inv_detA;
1739 invA[0][1] = (A[0][2] * A[2][1] - A[0][1] * A[2][2]) * inv_detA;
1740 invA[0][2] = (A[0][1] * A[1][2] - A[0][2] * A[1][1]) * inv_detA;
1741 invA[1][0] = (A[1][2] * A[2][0] - A[1][0] * A[2][2]) * inv_detA;
1742 invA[1][1] = (A[0][0] * A[2][2] - A[0][2] * A[2][0]) * inv_detA;
1743 invA[1][2] = (A[0][2] * A[1][0] - A[0][0] * A[1][2]) * inv_detA;
1744 invA[2][0] = (A[1][0] * A[2][1] - A[1][1] * A[2][0]) * inv_detA;
1745 invA[2][1] = (A[0][1] * A[2][0] - A[0][0] * A[2][1]) * inv_detA;
1746 invA[2][2] = (A[0][0] * A[1][1] - A[0][1] * A[1][0]) * inv_detA;
1755template <
typename T,
int n>
1757typename std::enable_if<(n > 3), tensor<T, n, n>>::type
1760 auto abs = [](T x) {
return (x < 0) ? -x : x; };
1770 for (
int i = 0; i < n; i++)
1773 T max_val =
abs(A[i][i]);
1776 for (
int j = i + 1; j < n; j++)
1778 if (
abs(A[j][i]) > max_val)
1780 max_val =
abs(A[j][i]);
1785 swap(B[max_row], B[i]);
1786 swap(A[max_row], A[i]);
1789 for (
int j = i + 1; j < n; j++)
1793 T c = -A[j][i] / A[i][i];
1802 for (
int i = n - 1; i >= 0; i--)
1804 B[i] = B[i] / A[i][i];
1805 for (
int j = i - 1; j >= 0; j--)
1809 B[j] -= A[j][i] * B[i];
1826template <
typename value_type,
typename gradient_type,
int n> MFEM_HOST_DEVICE
1831 return make_tensor<n, n>([&](
int i,
int j)
1833 auto value = invA[i][j];
1834 gradient_type gradient{};
1835 for (
int k = 0; k < n; k++)
1837 for (
int l = 0; l < n; l++)
1839 gradient -= invA[i][k] * A[k][l].gradient * invA[l][j];
1854template <
typename T,
int... n>
1858 for (
int i = 1; i <
tensor<T, n...>::first_dim; i++)
1870template <
int n> MFEM_HOST_DEVICE
1874 for (
int i = 0; i < n; i++)
1885template <
int m,
int n> MFEM_HOST_DEVICE
1889 for (
int i = 0; i < m; i++)
1891 for (
int j = 0; j < n; j++)
1893 if (
copy[i][j] *
copy[i][j] < 1.0e-20)
1905template <
typename T1,
typename T2>
1908template <
int... m,
int... n>
1909struct outer_prod<tensor<
real_t, m...>, tensor<
real_t, n...>>
1911 using type = tensor<
real_t, m..., n...>;
1917 using type = tensor<
real_t, n...>;
1929 using type = tensor<real_t>;
1932template <
typename T>
1933struct outer_prod<zero, T>
1938template <
typename T>
1939struct outer_prod<T, zero>
1952template <
typename T1,
typename T2>
1982template <
typename T>
1993template <
typename T>
2005 const real_t dx) {
return df_dx * dx; }
2023template <
typename T,
int n>
2027 "error: there is no such thing as a rank-1 isotropic tensor!");
2031template <
typename T,
int m>
2036 return (i == j) * value;
2047template <
typename S,
typename T,
int m> MFEM_HOST_DEVICE
constexpr
2052 return {I.value * scale};
2055template <
typename S,
typename T,
int m> MFEM_HOST_DEVICE
constexpr
2060 return {I.value * scale};
2063template <
typename S,
typename T,
int m> MFEM_HOST_DEVICE
constexpr
2068 return {I1.value + I2.value};
2071template <
typename S,
typename T,
int m> MFEM_HOST_DEVICE
constexpr
2076 return {I1.value - I2.value};
2079template <
typename S,
typename T,
int m> MFEM_HOST_DEVICE
2082->
tensor<
decltype(S {} + T{}), m, m>
2084 tensor<
decltype(S{} + T{}), m, m> output{};
2085 for (
int i = 0; i < m; i++)
2087 for (
int j = 0; j < m; j++)
2089 output[i][j] = I.value * (i == j) + A[i][j];
2095template <
typename S,
typename T,
int m> MFEM_HOST_DEVICE
2098->
tensor<
decltype(S {} + T{}), m, m>
2100 tensor<
decltype(S{} + T{}), m, m> output{};
2101 for (
int i = 0; i < m; i++)
2103 for (
int j = 0; j < m; j++)
2105 output[i][j] = A[i][j] + I.value * (i == j);
2111template <
typename S,
typename T,
int m> MFEM_HOST_DEVICE
2114->
tensor<
decltype(S {} - T{}), m, m>
2116 tensor<
decltype(S{} - T{}), m, m> output{};
2117 for (
int i = 0; i < m; i++)
2119 for (
int j = 0; j < m; j++)
2121 output[i][j] = I.value * (i == j) - A[i][j];
2127template <
typename S,
typename T,
int m> MFEM_HOST_DEVICE
2130->
tensor<
decltype(S {} - T{}), m, m>
2132 tensor<
decltype(S{} - T{}), m, m> output{};
2133 for (
int i = 0; i < m; i++)
2135 for (
int j = 0; j < m; j++)
2137 output[i][j] = A[i][j] - I.value * (i == j);
2143template <
typename S,
typename T,
int m,
int... n> MFEM_HOST_DEVICE
constexpr
2146->
tensor<
decltype(S {} * T{}), m, n...>
2151template <
typename S,
typename T,
int m,
int... n> MFEM_HOST_DEVICE
2154->
tensor<
decltype(S {} * T{}), n...>
2156 constexpr int dimensions[
sizeof...(n)] = {n...};
2157 static_assert(dimensions[
sizeof...(n) - 1] == m,
"n-1 != m");
2161template <
typename S,
typename T,
int m,
int... n> MFEM_HOST_DEVICE
constexpr
2164->
decltype(S {} * T{})
2166 return I.value * tr(A);
2169template <
typename T,
int m> MFEM_HOST_DEVICE
constexpr
2175template <
typename T,
int m> MFEM_HOST_DEVICE
constexpr
2181template <
typename T,
int m> MFEM_HOST_DEVICE
constexpr
2187template <
typename T,
int m> MFEM_HOST_DEVICE
constexpr
2193template <
typename T,
int m> MFEM_HOST_DEVICE
constexpr
2196 return std::pow(I.value, m);
2199template <
typename T,
int m> MFEM_HOST_DEVICE
constexpr
2202 return sqrt(I.value * I.value * m);
2205template <
typename T,
int m> MFEM_HOST_DEVICE
constexpr
2208 return I.value * I.value * m;
2212template <
typename T>
2215 MFEM_HOST_DEVICE
constexpr T
operator()(
int i,
int j,
int k)
const
2217 return 0.5 * (i - j) * (j - k) * (k - i) * value;
2224template <
typename T,
int m>
2229 MFEM_HOST_DEVICE
constexpr T
operator()(
int i,
int j,
int k,
int l)
const
2231 return c1 * (i == j) * (k == l)
2232 + c2 * ((i == k) * (j == l) + (i == l) * (j == k)) * 0.5
2233 + c3 * ((i == k) * (j == l) - (i == l) * (j == k)) * 0.5;
2237template <
int m> MFEM_HOST_DEVICE
constexpr
2240 return {0.0, 1.0, 0.0};
2243template <
int m>MFEM_HOST_DEVICE
constexpr
2246 return {0.0, 0.0, 1.0};
2249template <
typename S,
typename T,
int m> MFEM_HOST_DEVICE
constexpr
2254 return {I.c1 * scale, I.c2 * scale, I.c3 * scale};
2257template <
typename S,
typename T,
int m> MFEM_HOST_DEVICE
constexpr
2262 return {I.c1 * scale, I.c2 * scale, I.c3 * scale};
2265template <
typename S,
typename T,
int m> MFEM_HOST_DEVICE
constexpr
2270 return {I1.c1 + I2.c1, I1.c2 + I2.c2, I1.c3 + I2.c3};
2273template <
typename S,
typename T,
int m> MFEM_HOST_DEVICE
constexpr
2278 return {I1.c1 - I2.c1, I1.c2 - I2.c2, I1.c3 - I2.c3};
2281template <
typename S,
typename T,
int m,
int... n> MFEM_HOST_DEVICE
constexpr
2284->
tensor<
decltype(S {} * T{}), m, m>
2286 return I.c1 * tr(A) * IdentityMatrix<m>() + I.c2 * sym(A) + I.c3 * antisym(A);
This file contains the declaration of a dual number class.
ostream & operator<<(ostream &v, void(*f)(VisMan &))
MFEM_HOST_DEVICE constexpr auto operator-(dual< value_type, gradient_type > x) -> dual< value_type, gradient_type >
unary negation of a dual number
MFEM_HOST_DEVICE constexpr auto operator+(dual< value_type, gradient_type > a, other_type b) -> dual< value_type, gradient_type >
addition of a dual number and a non-dual number
MFEM_HOST_DEVICE auto ddot(const tensor< S, m, n, p, q > &A, const tensor< T, p, q > &B) -> tensor< decltype(S {} *T{}), m, n >
real_t dot product, contracting over the two "middle" indices
MFEM_HOST_DEVICE T get_value(const T &arg)
return the "value" part from a given type. For non-dual types, this is just the identity function
MFEM_HOST_DEVICE T sqnorm(const tensor< T, m > &A)
Returns the squared Frobenius norm of the tensor.
gradient_type MFEM_HOST_DEVICE dual< value_type, gradient_type > & operator+=(dual< value_type, gradient_type > &a, const dual< value_type, gradient_type > &b)
MFEM_HOST_DEVICE tensor< T, n > linear_solve(tensor< T, n, n > A, const tensor< T, n > b)
Solves Ax = b for x using Gaussian elimination with partial pivoting.
MFEM_HOST_DEVICE constexpr isotropic_tensor< real_t, m, m > IsotropicIdentity()
MFEM_HOST_DEVICE constexpr auto AntisymmetricIdentity() -> isotropic_tensor< real_t, m, m, m, m >
MFEM_HOST_DEVICE void copy(DeviceTensor< n > &u, DeviceTensor< n > &v)
Copy data from DeviceTensor u to DeviceTensor v.
MFEM_HOST_DEVICE auto outer(S A, T B) -> decltype(A *B)
compute the outer product of two tensors
MFEM_HOST_DEVICE void GetScalingFactor(const T &d_max, T &mult)
MFEM_HOST_DEVICE auto normalize(const tensor< T, n... > &A) -> decltype(A/norm(A))
Normalizes the tensor Each element is divided by the Frobenius norm of the tensor,...
MFEM_HOST_DEVICE T det(const tensor< T, 1, 1 > &A)
Returns the determinant of a matrix.
MFEM_HOST_DEVICE T tr(const tensor< T, n, n > &A)
Returns the trace of a square matrix.
MFEM_HOST_DEVICE auto inner(const tensor< S, m, n > &A, const tensor< T, m, n > &B) -> decltype(S {} *T{})
this function contracts over all indices of the two tensor arguments
MFEM_HOST_DEVICE constexpr auto SymmetricIdentity() -> isotropic_tensor< real_t, m, m, m, m >
typename detail::outer_prod< T1, T2 >::type outer_product_t
a type function that returns the tensor type of an outer product of two tensors
MFEM_HOST_DEVICE constexpr auto antisym(const isotropic_tensor< T, m, m > &) -> zero
MFEM_HOST_DEVICE dual< value_type, gradient_type > & operator-=(dual< value_type, gradient_type > &a, const dual< value_type, gradient_type > &b)
compound assignment (-) for dual numbers
MFEM_HOST_DEVICE T weight(const tensor< T, n, m > &A)
MFEM_HOST_DEVICE tensor< real_t, n > chop(const tensor< real_t, n > &A)
replace all entries in a tensor satisfying |x| < 1.0e-10 by literal zero
MFEM_HOST_DEVICE tensor< real_t, dim, dim > IdentityMatrix()
Obtains the identity matrix of the specified dimension.
MFEM_HOST_DEVICE constexpr auto make_tensor(lambda_type f) -> tensor< decltype(f())>
Creates a tensor of requested dimension by subsequent calls to a functor Can be thought of as analogo...
MFEM_HOST_DEVICE T calcsv(const tensor< T, 1, 1 > A, const int i)
MFEM_HOST_DEVICE constexpr auto type(const tuple< T... > &values)
a function intended to be used for extracting the ith type from a tuple.
MFEM_HOST_DEVICE zero chain_rule(const zero, const zero)
evaluate the change (to first order) in a function, f, given a small change in the input argument,...
MFEM_HOST_DEVICE tensor< T, n+m > flatten(tensor< T, n, m > A)
MFEM_HOST_DEVICE tensor< T, 1, 1 > inv(const tensor< T, 1, 1 > &A)
Inverts a matrix.
MFEM_HOST_DEVICE tensor< T, n, n > dev(const tensor< T, n, n > &A)
Calculates the deviator of a matrix (rank-2 tensor)
MFEM_HOST_DEVICE tensor< T, n, m > transpose(const tensor< T, m, n > &A)
Returns the transpose of the matrix.
typename std::conditional<(n1==1 &&n2==1), T, typename std::conditional< n1==1, tensor< T, n2 >, typename std::conditional< n2==1, tensor< T, n1 >, tensor< T, n1, n2 > >::type >::type >::type reduced_tensor
Removes 1s from tensor dimensions For example, a tensor<T, 1, 10> is equivalent to a tensor<T,...
MFEM_HOST_DEVICE bool is_symmetric(tensor< real_t, n, n > A, real_t abs_tolerance=1.0e-8_r)
Return whether a square rank 2 tensor is symmetric.
MFEM_HOST_DEVICE dual< value_type, gradient_type > sqrt(dual< value_type, gradient_type > x)
implementation of square root for dual numbers
MFEM_HOST_DEVICE std::tuple< tensor< T, 1 >, tensor< T, 1, 1 > > eig(tensor< T, 1, 1 > &A)
MFEM_HOST_DEVICE tensor< T, n, n > sym(const tensor< T, n, n > &A)
Returns the symmetric part of a square matrix.
MFEM_HOST_DEVICE zero dot(const T &, zero)
the dot product of anything with zero is zero
MFEM_HOST_DEVICE tensor< T, n > get_col(tensor< T, m, n > A, int j)
MFEM_HOST_DEVICE constexpr auto operator*(const dual< value_type, gradient_type > &a, real_t b) -> dual< decltype(a.value *b), decltype(a.gradient *b)>
multiplication of a dual number and a non-dual number
MFEM_HOST_DEVICE constexpr auto operator/(const dual< value_type, gradient_type > &a, real_t b) -> dual< decltype(a.value/b), decltype(a.gradient/b)>
division of a dual number by a non-dual number
MFEM_HOST_DEVICE zero & get(zero &x)
let zero be accessed like a tuple
MFEM_HOST_DEVICE gradient_type get_gradient(dual< value_type, gradient_type > arg)
return the "gradient" part from a dual number type
MFEM_HOST_DEVICE bool is_symmetric_and_positive_definite(tensor< real_t, 2, 2 > A)
Return whether a matrix is symmetric and positive definite This check uses Sylvester's criterion,...
void swap(Array< T > &a, Array< T > &b)
Swap of Array<T> objects for use with standard library algorithms. Also, used by mfem::Swap().
real_t u(const Vector &xvec)
std::function< real_t(const Vector &)> f(real_t mass_coeff)
real_t p(const Vector &x, real_t t)
MFEM_HOST_DEVICE real_t norm(const Complex &z)
MFEM_HOST_DEVICE Complex operator+(const Complex &a, const Complex &b)
MFEM_HOST_DEVICE Complex operator*(const Complex &x, const real_t &y)
MFEM_HOST_DEVICE real_t abs(const Complex &z)
MFEM_HOST_DEVICE Complex operator/(const Complex &z, const real_t &d)
Dual number struct (value plus gradient)
MFEM_HOST_DEVICE constexpr T operator()(int i, int j, int k) const
MFEM_HOST_DEVICE constexpr T operator()(int i, int j, int k, int l) const
MFEM_HOST_DEVICE constexpr T operator()(int i, int j) const
MFEM_HOST_DEVICE tensor< T, n1 > & operator[](int)
MFEM_HOST_DEVICE const tensor< T, n1 > & operator[](int) const
MFEM_HOST_DEVICE const tensor< T, n1 > & operator()(int) const
MFEM_HOST_DEVICE T & operator()(int, int j)
MFEM_HOST_DEVICE tensor< T, n1 > & operator()(int)
MFEM_HOST_DEVICE const T & operator()(int, int j) const
MFEM_HOST_DEVICE T & operator[](int)
MFEM_HOST_DEVICE const T & operator[](int) const
MFEM_HOST_DEVICE T & operator()(int)
MFEM_HOST_DEVICE const T & operator()(int) const
MFEM_HOST_DEVICE const tensor< T, n1, n2, n3, n4 > & operator()(int i) const
MFEM_HOST_DEVICE const tensor< T, n2, n3, n4 > & operator()(int i, int j) const
MFEM_HOST_DEVICE tensor< T, n3, n4 > & operator()(int i, int j, int k)
MFEM_HOST_DEVICE T & operator()(int i, int j, int k, int l, int m)
MFEM_HOST_DEVICE const tensor< T, n3, n4 > & operator()(int i, int j, int k) const
MFEM_HOST_DEVICE tensor< T, n2, n3, n4 > & operator()(int i, int j)
MFEM_HOST_DEVICE const tensor< T, n1, n2, n3, n4 > & operator[](int i) const
MFEM_HOST_DEVICE const tensor< T, n4 > & operator()(int i, int j, int k, int l) const
MFEM_HOST_DEVICE tensor< T, n1, n2, n3, n4 > & operator()(int i)
MFEM_HOST_DEVICE const T & operator()(int i, int j, int k, int l, int m) const
MFEM_HOST_DEVICE tensor< T, n1, n2, n3, n4 > & operator[](int i)
MFEM_HOST_DEVICE tensor< T, n4 > & operator()(int i, int j, int k, int l)
MFEM_HOST_DEVICE T & operator()(int i, int j, int k, int l)
MFEM_HOST_DEVICE tensor< T, n2, n3 > & operator()(int i, int j)
MFEM_HOST_DEVICE const tensor< T, n1, n2, n3 > & operator()(int i) const
MFEM_HOST_DEVICE const tensor< T, n1, n2, n3 > & operator[](int i) const
MFEM_HOST_DEVICE const tensor< T, n3 > & operator()(int i, int j, int k) const
MFEM_HOST_DEVICE const T & operator()(int i, int j, int k, int l) const
MFEM_HOST_DEVICE const tensor< T, n2, n3 > & operator()(int i, int j) const
MFEM_HOST_DEVICE tensor< T, n1, n2, n3 > & operator[](int i)
MFEM_HOST_DEVICE tensor< T, n1, n2, n3 > & operator()(int i)
MFEM_HOST_DEVICE tensor< T, n3 > & operator()(int i, int j, int k)
MFEM_HOST_DEVICE tensor< T, n2 > & operator()(int i, int j)
MFEM_HOST_DEVICE T & operator()(int i, int j, int k)
MFEM_HOST_DEVICE tensor< T, n1, n2 > & operator()(int i)
MFEM_HOST_DEVICE const tensor< T, n1, n2 > & operator()(int i) const
MFEM_HOST_DEVICE tensor< T, n1, n2 > & operator[](int i)
MFEM_HOST_DEVICE const tensor< T, n1, n2 > & operator[](int i) const
MFEM_HOST_DEVICE const tensor< T, n2 > & operator()(int i, int j) const
MFEM_HOST_DEVICE const T & operator()(int i, int j, int k) const
MFEM_HOST_DEVICE tensor< T, n1 > & operator[](int i)
MFEM_HOST_DEVICE const T & operator()(int i, int j) const
MFEM_HOST_DEVICE const tensor< T, n1 > & operator()(int i) const
MFEM_HOST_DEVICE tensor< T, n1 > & operator()(int i)
MFEM_HOST_DEVICE T & operator()(int i, int j)
MFEM_HOST_DEVICE const tensor< T, n1 > & operator[](int i) const
MFEM_HOST_DEVICE T & operator()(int i)
MFEM_HOST_DEVICE const T & operator[](int i) const
MFEM_HOST_DEVICE const T & operator()(int i) const
MFEM_HOST_DEVICE T & operator[](int i)
MFEM_HOST_DEVICE const T & operator()(int) const
MFEM_HOST_DEVICE const T & operator[](int) const
MFEM_HOST_DEVICE T & operator()(int)
MFEM_HOST_DEVICE T & operator[](int)
A sentinel struct for eliding no-op tensor operations.
MFEM_HOST_DEVICE zero operator()(T...)
zero can be accessed like a multidimensional array
MFEM_HOST_DEVICE zero operator=(T)
anything assigned to zero does not change its value and returns zero