17#ifndef dealii_matrix_free_tensor_product_kernels_h
18#define dealii_matrix_free_tensor_product_kernels_h
122 typename Number2 = Number>
154 typename Number2 = Number>
189 static constexpr unsigned int n_rows_of_product =
191 static constexpr unsigned int n_columns_of_product =
210 const unsigned int dummy1 = 0,
211 const unsigned int dummy2 = 0)
212 : shape_values(shape_values.begin())
213 , shape_gradients(shape_gradients.begin())
214 , shape_hessians(shape_hessians.begin())
221 shape_values.
size() == n_rows * n_columns ||
222 shape_values.
size() == 3 * n_rows,
225 shape_gradients.
size() == n_rows * n_columns,
228 shape_hessians.
size() == n_rows * n_columns,
238 const Number2 * shape_gradients,
239 const Number2 * shape_hessians,
240 const unsigned int dummy1 = 0,
241 const unsigned int dummy2 = 0)
242 : shape_values(shape_values)
243 , shape_gradients(shape_gradients)
244 , shape_hessians(shape_hessians)
250 template <
int direction,
bool contract_over_rows,
bool add>
252 values(
const Number in[], Number out[])
const
257 template <
int direction,
bool contract_over_rows,
bool add>
264 template <
int direction,
bool contract_over_rows,
bool add>
271 template <
int direction,
bool contract_over_rows,
bool add>
279 template <
int direction,
bool contract_over_rows,
bool add>
287 template <
int direction,
bool contract_over_rows,
bool add>
319 template <
int direction,
378 template <
int direction,
bool contract_over_rows,
bool add,
bool one_line>
390 static_assert(
one_line ==
false || direction == dim - 1,
391 "Single-line evaluation only works for direction=dim-1.");
394 "The given array shape_data must not be the null pointer!"));
395 Assert(dim == direction + 1 ||
one_line ==
true || n_rows == n_columns ||
397 ExcMessage(
"In-place operation only supported for "
398 "n_rows==n_columns or single-line interpolation"));
406 Utilities::pow(n_rows, (direction >= dim) ? 0 : (dim - direction - 1));
413 for (
int i = 0; i <
mm; ++i)
414 x[i] = in[stride * i];
415 for (
int col = 0; col <
nn; ++col)
423 for (
int i = 1; i <
mm; ++i)
432 out[stride * col] +=
res0;
434 out[stride * col] =
res0;
445 in += stride * (
mm - 1);
446 out += stride * (
nn - 1);
474 "Only derivative orders 0-2 implemented");
475 Assert(shape_values !=
nullptr,
477 "The given array shape_values must not be the null pointer."));
479 constexpr int n_blocks1 = (dim > 1 ? n_rows : 1);
480 constexpr int n_blocks2 = (dim > 2 ? n_rows : 1);
493 Number
res0 = shape_values[0] * in[0];
496 res1 = shape_values[n_rows] * in[0];
498 res2 = shape_values[2 * n_rows] * in[0];
527 for (
int col = 0; col < n_rows; ++col)
530 out[col *
in_stride] += shape_values[col] * in[0];
532 out[col *
in_stride] = shape_values[col] * in[0];
538 shape_values[col + 2 * n_rows] * in[2 *
out_stride];
579 in += n_rows * (n_rows - 1);
580 out -= n_rows * n_rows - 1;
584 out += n_rows * (n_rows - 1);
585 in -= n_rows * n_rows - 1;
606 template <
int dim,
typename Number,
typename Number2>
609 static constexpr unsigned int n_rows_of_product =
611 static constexpr unsigned int n_columns_of_product =
622 , n_rows(
numbers::invalid_unsigned_int)
623 , n_columns(
numbers::invalid_unsigned_int)
632 const unsigned int n_rows,
633 const unsigned int n_columns)
634 : shape_values(shape_values.begin())
635 , shape_gradients(shape_gradients.begin())
636 , shape_hessians(shape_hessians.begin())
638 , n_columns(n_columns)
645 shape_values.
size() == n_rows * n_columns ||
646 shape_values.
size() == n_rows * 3,
649 shape_gradients.
size() == n_rows * n_columns,
652 shape_hessians.
size() == n_rows * n_columns,
660 const Number2 * shape_gradients,
661 const Number2 * shape_hessians,
662 const unsigned int n_rows,
663 const unsigned int n_columns)
664 : shape_values(shape_values)
665 , shape_gradients(shape_gradients)
666 , shape_hessians(shape_hessians)
668 , n_columns(n_columns)
671 template <
int direction,
bool contract_over_rows,
bool add>
673 values(
const Number *in, Number *out)
const
678 template <
int direction,
bool contract_over_rows,
bool add>
685 template <
int direction,
bool contract_over_rows,
bool add>
692 template <
int direction,
bool contract_over_rows,
bool add>
700 template <
int direction,
bool contract_over_rows,
bool add>
708 template <
int direction,
bool contract_over_rows,
bool add>
716 template <
int direction,
742 template <
int dim,
typename Number,
typename Number2>
743 template <
int direction,
bool contract_over_rows,
bool add,
bool one_line>
750 static_assert(
one_line ==
false || direction == dim - 1,
751 "Single-line evaluation only works for direction=dim-1.");
754 "The given array shape_data must not be the null pointer!"));
755 Assert(dim == direction + 1 ||
one_line ==
true || n_rows == n_columns ||
757 ExcMessage(
"In-place operation only supported for "
758 "n_rows==n_columns or single-line interpolation"));
764 direction == 0 ? 1 : Utilities::fixed_power<direction>(n_columns);
766 const int n_blocks2 = direction >= dim - 1 ?
783 const Number
x0 = in[0],
x1 = in[stride];
784 for (
int col = 0; col <
nn; ++col)
789 out[stride * col] +=
result;
791 out[stride * col] =
result;
802 in += stride * (
mm - 1);
803 out += stride * (
nn - 1);
816 const Number
x0 = in[0],
x1 = in[stride],
x2 = in[2 * stride];
817 for (
int col = 0; col <
nn; ++col)
823 out[stride * col] +=
result;
825 out[stride * col] =
result;
836 in += stride * (
mm - 1);
837 out += stride * (
nn - 1);
848 for (
int i = 0; i <
mm; ++i)
849 x[i] = in[stride * i];
850 for (
int col = 0; col <
nn; ++col)
858 for (
int i = 1; i <
mm; ++i)
867 out[stride * col] +=
res0;
869 out[stride * col] =
res0;
880 in += stride * (
mm - 1);
881 out += stride * (
nn - 1);
888 template <
int dim,
typename Number,
typename Number2>
898 Assert(shape_values !=
nullptr,
900 "The given array shape_data must not be the null pointer!"));
901 static_assert(dim > 0 && dim < 4,
"Only dim=1,2,3 supported");
902 const int n_blocks1 = dim > 1 ? n_rows : 1;
903 const int n_blocks2 = dim > 2 ? n_rows : 1;
907 face_direction > 0 ? Utilities::fixed_power<face_direction>(n_rows) : 1;
917 Number
res0 = shape_values[0] * in[0];
920 res1 = shape_values[n_rows] * in[0];
922 res2 = shape_values[2 * n_rows] * in[0];
923 for (
unsigned int ind = 1;
ind < n_rows; ++
ind)
951 for (
unsigned int col = 0; col < n_rows; ++col)
954 out[col *
in_stride] += shape_values[col] * in[0];
956 out[col *
in_stride] = shape_values[col] * in[0];
962 shape_values[col + 2 * n_rows] * in[2 *
out_stride];
1002 in += n_rows * (n_rows - 1);
1003 out -= n_rows * n_rows - 1;
1007 out += n_rows * (n_rows - 1);
1008 in -= n_rows * n_rows - 1;
1048 static constexpr unsigned int n_rows_of_product =
1050 static constexpr unsigned int n_columns_of_product =
1059 const unsigned int dummy1 = 0,
1060 const unsigned int dummy2 = 0)
1061 : shape_values(shape_values.begin())
1062 , shape_gradients(shape_gradients.begin())
1063 , shape_hessians(shape_hessians.begin())
1066 shape_values.
size() == n_rows * n_columns,
1069 shape_gradients.
size() == n_rows * n_columns,
1072 shape_hessians.
size() == n_rows * n_columns,
1078 template <
int direction,
bool contract_over_rows,
bool add>
1080 values(
const Number in[], Number out[])
const;
1082 template <
int direction,
bool contract_over_rows,
bool add>
1084 gradients(
const Number in[], Number out[])
const;
1086 template <
int direction,
bool contract_over_rows,
bool add>
1088 hessians(
const Number in[], Number out[])
const;
1121 template <
int direction,
bool contract_over_rows,
bool add>
1128 Number2>::values(
const Number in[], Number out[])
const
1134 constexpr int n_cols =
nn / 2;
1135 constexpr int mid =
mm / 2;
1140 Utilities::pow(n_rows, (direction >= dim) ? 0 : (dim - direction - 1));
1146 for (
int col = 0; col < n_cols; ++col)
1152 val0 = shape_values[col];
1153 val1 = shape_values[
nn - 1 - col];
1157 val0 = shape_values[col * n_columns];
1158 val1 = shape_values[(col + 1) * n_columns - 1];
1163 in1 = in[stride * (
mm - 1)];
1172 val0 = shape_values[
ind * n_columns + col];
1173 val1 = shape_values[
ind * n_columns +
nn - 1 - col];
1177 val0 = shape_values[col * n_columns +
ind];
1179 shape_values[(col + 1) * n_columns - 1 -
ind];
1195 val0 = shape_values[
mid * n_columns + col];
1203 if (
mm % 2 == 1 &&
nn % 2 == 0)
1205 val0 = shape_values[col * n_columns +
mid];
1213 out[stride * col] +=
res0;
1214 out[stride * (
nn - 1 - col)] +=
res1;
1218 out[stride * col] =
res0;
1219 out[stride * (
nn - 1 - col)] =
res1;
1225 out[stride * n_cols] += in[stride *
mid];
1227 out[stride * n_cols] = in[stride *
mid];
1232 Number2
val0 = shape_values[n_cols];
1235 res0 =
val0 * (in[0] + in[stride * (
mm - 1)]);
1238 val0 = shape_values[
ind * n_columns + n_cols];
1240 in[stride * (
mm - 1 -
ind)]);
1246 out[stride * n_cols] +=
res0;
1248 out[stride * n_cols] =
res0;
1255 Number2
val0 = shape_values[n_cols * n_columns];
1256 res0 =
val0 * (in[0] + in[stride * (
mm - 1)]);
1259 val0 = shape_values[n_cols * n_columns +
ind];
1261 in[stride * (
mm - 1 -
ind)]);
1270 out[stride * n_cols] +=
res0;
1272 out[stride * n_cols] =
res0;
1278 in += stride * (
mm - 1);
1279 out += stride * (
nn - 1);
1309 template <
int direction,
bool contract_over_rows,
bool add>
1316 Number2>::gradients(
const Number in[],
1323 constexpr int n_cols =
nn / 2;
1324 constexpr int mid =
mm / 2;
1329 Utilities::pow(n_rows, (direction >= dim) ? 0 : (dim - direction - 1));
1335 for (
int col = 0; col < n_cols; ++col)
1341 val0 = shape_gradients[col];
1342 val1 = shape_gradients[
nn - 1 - col];
1346 val0 = shape_gradients[col * n_columns];
1347 val1 = shape_gradients[(
nn - col - 1) * n_columns];
1352 in1 = in[stride * (
mm - 1)];
1361 val0 = shape_gradients[
ind * n_columns + col];
1363 shape_gradients[
ind * n_columns +
nn - 1 - col];
1367 val0 = shape_gradients[col * n_columns +
ind];
1369 shape_gradients[(
nn - col - 1) * n_columns +
ind];
1384 val0 = shape_gradients[
mid * n_columns + col];
1386 val0 = shape_gradients[col * n_columns +
mid];
1393 out[stride * col] +=
res0;
1394 out[stride * (
nn - 1 - col)] +=
res1;
1398 out[stride * col] =
res0;
1399 out[stride * (
nn - 1 - col)] =
res1;
1407 val0 = shape_gradients[n_cols];
1409 val0 = shape_gradients[n_cols * n_columns];
1410 res0 =
val0 * (in[0] - in[stride * (
mm - 1)]);
1414 val0 = shape_gradients[
ind * n_columns + n_cols];
1416 val0 = shape_gradients[n_cols * n_columns +
ind];
1418 val0 * (in[stride *
ind] - in[stride * (
mm - 1 -
ind)]);
1422 out[stride * n_cols] +=
res0;
1424 out[stride * n_cols] =
res0;
1430 in += stride * (
mm - 1);
1431 out += stride * (
nn - 1);
1445 template <
int direction,
bool contract_over_rows,
bool add>
1452 Number2>::hessians(
const Number in[],
1459 constexpr int n_cols =
nn / 2;
1460 constexpr int mid =
mm / 2;
1465 Utilities::pow(n_rows, (direction >= dim) ? 0 : (dim - direction - 1));
1471 for (
int col = 0; col < n_cols; ++col)
1477 val0 = shape_hessians[col];
1478 val1 = shape_hessians[
nn - 1 - col];
1482 val0 = shape_hessians[col * n_columns];
1483 val1 = shape_hessians[(col + 1) * n_columns - 1];
1488 in1 = in[stride * (
mm - 1)];
1497 val0 = shape_hessians[
ind * n_columns + col];
1499 shape_hessians[
ind * n_columns +
nn - 1 - col];
1503 val0 = shape_hessians[col * n_columns +
ind];
1505 shape_hessians[(col + 1) * n_columns - 1 -
ind];
1520 val0 = shape_hessians[
mid * n_columns + col];
1522 val0 = shape_hessians[col * n_columns +
mid];
1529 out[stride * col] +=
res0;
1530 out[stride * (
nn - 1 - col)] +=
res1;
1534 out[stride * col] =
res0;
1535 out[stride * (
nn - 1 - col)] =
res1;
1543 val0 = shape_hessians[n_cols];
1545 val0 = shape_hessians[n_cols * n_columns];
1548 res0 =
val0 * (in[0] + in[stride * (
mm - 1)]);
1552 val0 = shape_hessians[
ind * n_columns + n_cols];
1554 val0 = shape_hessians[n_cols * n_columns +
ind];
1556 in[stride * (
mm - 1 -
ind)]);
1565 val0 = shape_hessians[
mid * n_columns + n_cols];
1567 val0 = shape_hessians[n_cols * n_columns +
mid];
1571 out[stride * n_cols] +=
res0;
1573 out[stride * n_cols] =
res0;
1579 in += stride * (
mm - 1);
1580 out += stride * (
nn - 1);
1603 static_assert(type < 3,
"Only three variants type=0,1,2 implemented");
1604 static_assert(
one_line ==
false || direction == dim - 1,
1605 "Single-line evaluation only works for direction=dim-1.");
1608 const int n_columns =
1611 Assert(dim == direction + 1 ||
one_line ==
true || n_rows == n_columns ||
1613 ExcMessage(
"In-place operation only supported for "
1614 "n_rows==n_columns or single-line interpolation"));
1624 const int n_cols =
nn / 2;
1625 const int mid =
mm / 2;
1635 Utilities::pow(n_rows, (direction >= dim) ? 0 : (dim - direction - 1));
1637 const int offset = (n_columns + 1) / 2;
1652 for (
int i = 0; i <
mid; ++i)
1656 xp[i] = in[stride * i] - in[stride * (
mm - 1 - i)];
1657 xm[i] = in[stride * i] + in[stride * (
mm - 1 - i)];
1661 xp[i] = in[stride * i] + in[stride * (
mm - 1 - i)];
1662 xm[i] = in[stride * i] - in[stride * (
mm - 1 - i)];
1665 Number
xmid = in[stride *
mid];
1666 for (
int col = 0; col < n_cols; ++col)
1673 r0 = shapes[col] *
xp[0];
1674 r1 = shapes[(n_rows - 1) * offset + col] *
xm[0];
1678 r0 = shapes[col * offset] *
xp[0];
1679 r1 = shapes[(n_rows - 1 - col) * offset] *
xm[0];
1686 r1 += shapes[(n_rows - 1 -
ind) * offset + col] *
1692 r1 += shapes[(n_rows - 1 - col) * offset +
ind] *
1702 r1 += shapes[
mid * offset + col] *
xmid;
1704 r0 += shapes[
mid * offset + col] *
xmid;
1706 else if (
mm % 2 == 1 && (
nn % 2 == 0 || type > 0 ||
mm == 3))
1707 r0 += shapes[col * offset +
mid] *
xmid;
1711 out[stride * col] +=
r0 +
r1;
1713 out[stride * (
nn - 1 - col)] +=
r1 -
r0;
1715 out[stride * (
nn - 1 - col)] +=
r0 -
r1;
1719 out[stride * col] =
r0 +
r1;
1721 out[stride * (
nn - 1 - col)] =
r1 -
r0;
1723 out[stride * (
nn - 1 - col)] =
r0 -
r1;
1727 mm % 2 == 1 &&
mm > 3)
1730 out[stride * n_cols] += shapes[
mid * offset + n_cols] *
xmid;
1732 out[stride * n_cols] = shapes[
mid * offset + n_cols] *
xmid;
1739 r0 = shapes[n_cols] *
xp[0];
1741 r0 += shapes[
ind * offset + n_cols] *
xp[
ind];
1745 if (type != 1 &&
mm % 2 == 1)
1746 r0 += shapes[
mid * offset + n_cols] *
xmid;
1749 out[stride * n_cols] +=
r0;
1751 out[stride * n_cols] =
r0;
1760 r0 = shapes[n_cols * offset] *
xm[0];
1762 r0 += shapes[n_cols * offset +
ind] *
xm[
ind];
1766 r0 = shapes[n_cols * offset] *
xp[0];
1768 r0 += shapes[n_cols * offset +
ind] *
xp[
ind];
1774 if ((type == 0 || type == 2) &&
mm % 2 == 1)
1775 r0 += shapes[n_cols * offset +
mid] *
xmid;
1778 out[stride * n_cols] +=
r0;
1780 out[stride * n_cols] =
r0;
1790 in += stride * (
mm - 1);
1791 out += stride * (
nn - 1);
1841 static constexpr unsigned int n_rows_of_product =
1843 static constexpr unsigned int n_columns_of_product =
1862 : shape_values(shape_values.begin())
1876 const unsigned int dummy1 = 0,
1877 const unsigned int dummy2 = 0)
1878 : shape_values(shape_values.begin())
1879 , shape_gradients(shape_gradients.begin())
1880 , shape_hessians(shape_hessians.begin())
1884 if (!shape_values.
empty())
1886 if (!shape_gradients.
empty())
1888 if (!shape_hessians.
empty())
1894 template <
int direction,
bool contract_over_rows,
bool add>
1896 values(
const Number in[], Number out[])
const
1902 template <
int direction,
bool contract_over_rows,
bool add>
1910 template <
int direction,
bool contract_over_rows,
bool add>
1918 template <
int direction,
bool contract_over_rows,
bool add>
1926 template <
int direction,
bool contract_over_rows,
bool add>
1936 template <
int direction,
bool contract_over_rows,
bool add>
1974 template <
int direction,
2009 template <
int dim,
typename Number,
typename Number2>
2016 , n_rows(
numbers::invalid_unsigned_int)
2017 , n_columns(
numbers::invalid_unsigned_int)
2021 const unsigned int n_rows = 0,
2022 const unsigned int n_columns = 0)
2023 : shape_values(shape_values.begin())
2027 , n_columns(n_columns)
2035 const unsigned int n_rows = 0,
2036 const unsigned int n_columns = 0)
2037 : shape_values(shape_values.begin())
2038 , shape_gradients(shape_gradients.begin())
2039 , shape_hessians(shape_hessians.begin())
2041 , n_columns(n_columns)
2043 if (!shape_values.
empty())
2045 if (!shape_gradients.
empty())
2047 if (!shape_hessians.
empty())
2051 template <
int direction,
bool contract_over_rows,
bool add>
2053 values(
const Number in[], Number out[])
const
2059 template <
int direction,
bool contract_over_rows,
bool add>
2067 template <
int direction,
bool contract_over_rows,
bool add>
2075 template <
int direction,
bool contract_over_rows,
bool add>
2083 template <
int direction,
bool contract_over_rows,
bool add>
2093 template <
int direction,
bool contract_over_rows,
bool add>
2103 template <
int direction,
2175 static constexpr unsigned int n_rows_of_product =
2177 static constexpr unsigned int n_columns_of_product =
2196 : shape_values(shape_values.begin())
2208 const unsigned int dummy1 = 0,
2209 const unsigned int dummy2 = 0)
2210 : shape_values(shape_values.begin())
2211 , shape_gradients(shape_gradients.begin())
2212 , shape_hessians(shape_hessians.begin())
2218 template <
int direction,
bool contract_over_rows,
bool add>
2220 values(
const Number in[], Number out[])
const
2226 template <
int direction,
bool contract_over_rows,
bool add>
2234 template <
int direction,
bool contract_over_rows,
bool add>
2242 template <
int direction,
bool contract_over_rows,
bool add>
2250 template <
int direction,
bool contract_over_rows,
bool add>
2260 template <
int direction,
bool contract_over_rows,
bool add>
2297 template <
int direction,
2320 template <
int direction,
2335 static_assert(
one_line ==
false || direction == dim - 1,
2336 "Single-line evaluation only works for direction=dim-1.");
2338 type == 0 || type == 1,
2339 "Only types 0 and 1 implemented for evaluate_symmetric_hierarchical.");
2340 Assert(dim == direction + 1 ||
one_line ==
true || n_rows == n_columns ||
2342 ExcMessage(
"In-place operation only supported for "
2343 "n_rows==n_columns or single-line interpolation"));
2351 constexpr int n_cols =
nn / 2;
2352 constexpr int mid =
mm / 2;
2357 Utilities::pow(n_rows, (direction >= dim) ? 0 : (dim - direction - 1));
2370 for (
unsigned int i = 0; i <
mm; ++i)
2371 x[i] = in[stride * i];
2372 for (
unsigned int col = 0; col < n_cols; ++col)
2377 r0 = shapes[col] *
x[0];
2378 r1 = shapes[col + n_columns] *
x[1];
2382 shapes[col + 2 *
ind * n_columns] *
x[2 *
ind];
2383 r1 += shapes[col + (2 *
ind + 1) * n_columns] *
2390 r0 += shapes[col + (
mm - 1) * n_columns] *
x[
mm - 1];
2393 out[stride * col] +=
r0 +
r1;
2395 out[stride * (
nn - 1 - col)] +=
r1 -
r0;
2397 out[stride * (
nn - 1 - col)] +=
r0 -
r1;
2401 out[stride * col] =
r0 +
r1;
2403 out[stride * (
nn - 1 - col)] =
r1 -
r0;
2405 out[stride * (
nn - 1 - col)] =
r0 -
r1;
2411 const unsigned int shift = type == 1 ? 1 : 0;
2414 r0 = shapes[n_cols + shift * n_columns] *
x[shift];
2416 r0 += shapes[n_cols + (2 *
ind + shift) * n_columns] *
2421 if (type != 1 &&
mm % 2 == 1)
2422 r0 += shapes[n_cols + (
mm - 1) * n_columns] *
x[
mm - 1];
2424 out[stride * n_cols] +=
r0;
2426 out[stride * n_cols] =
r0;
2432 for (
int i = 0; i <
mid; ++i)
2435 xp[i] = in[stride * i] + in[stride * (
mm - 1 - i)];
2436 xm[i] = in[stride * i] - in[stride * (
mm - 1 - i)];
2440 xp[i] = in[stride * i] - in[stride * (
mm - 1 - i)];
2441 xm[i] = in[stride * i] + in[stride * (
mm - 1 - i)];
2445 for (
unsigned int col = 0; col < n_cols; ++col)
2450 r0 = shapes[2 * col * n_columns] *
xp[0];
2451 r1 = shapes[(2 * col + 1) * n_columns] *
xm[0];
2454 r0 += shapes[2 * col * n_columns +
ind] *
xp[
ind];
2456 shapes[(2 * col + 1) * n_columns +
ind] *
xm[
ind];
2465 shapes[(2 * col + 1) * n_columns +
mid] *
xp[
mid];
2467 r0 += shapes[2 * col * n_columns +
mid] *
xp[
mid];
2471 out[stride * (2 * col)] +=
r0;
2472 out[stride * (2 * col + 1)] +=
r1;
2476 out[stride * (2 * col)] =
r0;
2477 out[stride * (2 * col + 1)] =
r1;
2485 r0 = shapes[(
nn - 1) * n_columns] *
xp[0];
2491 if (
mm % 2 == 1 && type == 0)
2494 out[stride * (
nn - 1)] +=
r0;
2496 out[stride * (
nn - 1)] =
r0;
2507 in += stride * (
mm - 1);
2508 out += stride * (
nn - 1);
2548 static constexpr unsigned int n_rows_of_product =
2550 static constexpr unsigned int n_columns_of_product =
2570 const unsigned int dummy1 = 0,
2571 const unsigned int dummy2 = 0)
2572 : shape_values(shape_values.begin())
2573 , shape_gradients(shape_gradients.begin())
2574 , shape_hessians(shape_hessians.begin())
2581 shape_values.
size() == n_rows * n_columns ||
2582 shape_values.
size() == 3 * n_rows,
2585 shape_gradients.
size() == n_rows * n_columns,
2588 shape_hessians.
size() == n_rows * n_columns,
2594 template <
int direction,
bool contract_over_rows,
bool add>
2596 values(
const Number in[], Number out[])
const
2601 template <
int direction,
bool contract_over_rows,
bool add>
2608 template <
int direction,
bool contract_over_rows,
bool add>
2643 template <
int direction,
2672 template <
int direction,
bool contract_over_rows,
bool add,
bool one_line>
2685 static_assert(
one_line ==
false || direction == dim - 1,
2686 "Single-line evaluation only works for direction=dim-1.");
2689 "The given array shape_data must not be the null pointer!"));
2690 Assert(dim == direction + 1 ||
one_line ==
true || n_rows == n_columns ||
2692 ExcMessage(
"In-place operation only supported for "
2693 "n_rows==n_columns or single-line interpolation"));
2703 (dim - direction - 1 == 0) ?
2707 (direction >= dim) ? 0 : dim - direction - 1) :
2708 (((direction <
normal_dir) ? (n_rows + 1) : n_rows) *
2709 ((dim - direction == 3) ? n_rows : 1)));
2716 for (
int i = 0; i <
mm; ++i)
2717 x[i] = in[stride * i];
2719 for (
int col = 0; col <
nn; ++col)
2729 for (
int i = 1; i <
mm; ++i)
2739 out[stride * col] +=
res0;
2742 out[stride * col] =
res0;
2753 in += stride * (
mm - 1);
2754 out += stride * (
nn - 1);
2782 "Only derivative orders 0-2 implemented");
2783 Assert(shape_values !=
nullptr,
2785 "The given array shape_values must not be the null pointer."));
2813 n_rows * (n_rows + 1) :
2826 Number
res0 = shape_values[0] * in[0];
2830 res1 = shape_values[n_rows] * in[0];
2833 res2 = shape_values[2 * n_rows] * in[0];
2868 for (
int col = 0; col < n_rows; ++col)
2871 out[col *
in_stride] += shape_values[col] * in[0];
2873 out[col *
in_stride] = shape_values[col] * in[0];
2881 shape_values[col + 2 * n_rows] * in[2 *
out_stride];
2943 in += (n_rows + 1) * (n_rows - 1);
2944 out -= n_rows * (n_rows + 1) - 1;
2948 in += (n_rows - 1) * (n_rows - 1);
2949 out -= (n_rows - 1) * (n_rows - 1) - 1;
2953 in += (n_rows - 1) * (n_rows);
2954 out -= (n_rows) * (n_rows + 1) - 1;
2961 out += (n_rows + 1) * (n_rows - 1);
2962 in -= n_rows * (n_rows + 1) - 1;
2966 out += (n_rows - 1) * (n_rows - 1);
2967 in -= (n_rows - 1) * (n_rows - 1) - 1;
2971 out += (n_rows - 1) * (n_rows);
2972 in -= (n_rows) * (n_rows + 1) - 1;
2987 template <
typename Number,
typename Number2>
2993 template <
int dim,
typename Number,
typename Number2>
3005 template <
int dim,
typename Number>
3011 const unsigned int derivative = 1)
3016 std::array<Number, dim> point;
3017 for (
unsigned int d = 0; d < dim; ++d)
3020 poly[i].values_of_array(point, derivative, shapes[i].data());
3028 template <
typename Number>
3053 std::array<typename ProductTypeNoPoint<Number, Number2>::type,
3056 const std::vector<unsigned int> & renumber,
3061 static_assert(0 <= dim && dim <= 3,
"Only dim=0,1,2,3 implemented");
3062 static_assert(1 <= n_values && n_values <= 2,
3063 "Only n_values=1,2 implemented");
3076 std::array<Number3, 2 + n_values>
result = {};
3140 inline std::array<typename ProductTypeNoPoint<Number, Number2>::type,
3145 const Number * values,
3146 const std::vector<unsigned int> & renumber = {})
3148 static_assert(0 <= dim && dim <= 3,
"Only dim=0,1,2,3 implemented");
3149 static_assert(1 <= n_values && n_values <= 2,
3150 "Only n_values=1,2 implemented");
3154 std::array<Number3, dim + n_values>
result = {};
3176 values, renumber, shapes,
n_shapes, i);
3180 values, renumber, shapes,
n_shapes, i);
3184 values, renumber, shapes,
n_shapes, i);
3188 values, renumber, shapes,
n_shapes, i);
3192 values, renumber, shapes,
n_shapes, i);
3239 template <
int dim,
typename Number,
typename Number2,
int n_values = 1>
3240 inline std::array<typename ProductTypeNoPoint<Number, Number2>::type,
3244 const Number * values,
3246 const std::vector<unsigned int> &renumber = {})
3248 static_assert(0 <= dim && dim <= 3,
"Only dim=0,1,2,3 implemented");
3249 static_assert(1 <= n_values && n_values <= 2,
3250 "Only n_values=1,2 implemented");
3258 n_values > 1 ? values + Utilities::fixed_power<dim>(
n_shapes) :
nullptr;
3261 for (
unsigned int i = 0; i < renumber.
size(); ++i)
3264 std::array<Number3, dim + n_values>
result;
3370 template <
int dim,
typename Number,
typename Number2>
3376 const std::vector<Number> & values,
3379 const std::vector<unsigned int> & renumber = {})
3383 std::array<Number3, dim + 1>
result;
3387 poly.size(), values.data(), p, renumber);
3392 std::array<::ndarray<Number2, 2, dim>, 200> shapes;
3397 shapes.data(), poly.size(),
values.data(), renumber);
3399 return std::make_pair(
result[dim],
3417 const std::vector<unsigned int> & renumber,
3434 value += shapes[
i0][0][0] * values[renumber[i]];
3437 value += shapes[
i0][0][0] * values[i];
3449 template <
int dim,
typename Number,
typename Number2,
bool do_renumber = true>
3454 const Number * values,
3455 const std::vector<unsigned int> & renumber = {})
3457 static_assert(dim >= 0 && dim <= 3,
"Only dim=0,1,2,3 implemented");
3478 values, renumber, shapes,
n_shapes, i);
3482 values, renumber, shapes,
n_shapes, i);
3486 values, renumber, shapes,
n_shapes, i);
3490 values, renumber, shapes,
n_shapes, i);
3494 values, renumber, shapes,
n_shapes, i);
3515 template <
int dim,
typename Number,
typename Number2>
3519 const Number * values,
3521 const std::vector<unsigned int> &renumber = {})
3524 static_assert(dim >= 0 && dim <= 3,
"Only dim=0,1,2,3 implemented");
3529 for (
unsigned int i = 0; i < renumber.
size(); ++i)
3539 return Number3(values[0]) + p[0] *
Number3(values[1] - values[0]);
3572 template <
int dim,
typename Number,
typename Number2>
3576 const std::vector<Number> & values,
3579 const std::vector<unsigned int> & renumber = {})
3592 std::array<::ndarray<Number2, 2, dim>, 200> shapes;
3594 std::array<Number2, dim>
point;
3595 for (
unsigned int d = 0;
d < dim; ++
d)
3598 poly[i].values_of_array(point, 0, shapes[i].data());
3611 template <
int derivative_order,
typename Number,
typename Number2>
3615 const std::vector<Number> & values,
3617 const std::vector<unsigned int> & renumber = {})
3626 std::array<Number2, derivative_order + 1> shapes;
3628 if (renumber.
empty())
3649 template <
int derivative_order,
typename Number,
typename Number2>
3655 const std::vector<Number> & values,
3657 const std::vector<unsigned int> & renumber = {})
3660 constexpr int dim = 2;
3670 std::array<Number2, dim> point;
3671 for (
unsigned int d = 0; d < dim; ++d)
3680 if (renumber.
empty())
3687 result_x[d] += shapes[
i0][d][0] * values[renumber[i]];
3701 template <
int derivative_order,
typename Number,
typename Number2>
3707 const std::vector<Number> & values,
3709 const std::vector<unsigned int> & renumber = {})
3712 constexpr int dim = 3;
3724 std::array<Number2, dim> point;
3725 for (
unsigned int d = 0; d < dim; ++d)
3738 if (renumber.
empty())
3745 result_x[d] += shapes[
i0][d][0] * values[renumber[i]];
3767 template <
int dim,
typename Number,
typename Number2>
3771 const std::vector<Number> & values,
3773 const std::vector<unsigned int> & renumber = {})
3775 static_assert(dim >= 1 && dim <= 3,
"Only dim=1,2,3 implemented");
3788 for (
unsigned int d = 0, c = 0; d < 2; ++d)
3789 for (
unsigned int e = d; e < 2; ++e, ++c)
3793 for (
unsigned int d = 0; d < 2; ++d)
3825 static_assert(0 <= dim && dim <= 3,
"Only dim=0,1,2,3 implemented");
3826 static_assert(1 <= n_values && n_values <= 2,
3827 "Only n_values=1,2 implemented");
3833 constexpr unsigned int array_size = length > 0 ? length : 1;
3841 for (
int i1 = 0;
i1 < (dim > 1 ? length : 1); ++
i1)
3859 for (
int i0 = 0;
i0 < length; ++
i0)
3875 i += (dim > 1 ? length * length : length);
3934 const Number2 *
value,
3938 static_assert(0 <= dim && dim <= 3,
"Only dim=0,1,2,3 implemented");
3939 static_assert(1 <= n_values && n_values <= 2,
3940 "Only n_values=1,2 implemented");
3947 values[0] +=
value[0];
3949 values[0] =
value[0];
3953 values[1] +=
value[1];
3955 values[1] =
value[1];
3970 (dim > 1 ?
gradient[1] : Number2());
4017 const Number2 *
value,
4023 static_assert(0 <= dim && dim <= 3,
"Only dim=0,1,2,3 implemented");
4024 static_assert(1 <= n_values && n_values <= 2,
4025 "Only n_values=1,2 implemented");
4034 values[0] +=
value[0];
4036 values[0] =
value[0];
4040 values[1] +=
value[1];
4042 values[1] =
value[1];
4050 values[0] +=
value[0] - difference;
4051 values[1] += difference;
4055 values[0] =
value[0] - difference;
4056 values[1] = difference;
4177 template <
int dim,
typename Number,
typename Number2,
int n_values = 1>
4182 const Number2 *
value,
4230 template <
int dim,
int length,
typename Number2,
typename Number,
bool add>
4245 constexpr unsigned int array_size = length > 0 ? length : 1;
4249 for (
unsigned int i1 = 0;
i1 < (dim > 1 ? length : 1); ++
i1)
4255 for (
unsigned int i0 = 0;
i0 < length; ++
i0)
4263 i += (dim > 1 ? length * length : length);
4290 template <
int dim,
typename Number,
typename Number2,
bool add>
4295 const Number2 &
value,
4298 static_assert(dim >= 0 && dim <= 3,
"Only dim=0,1,2,3 implemented");
4347 template <
int dim,
typename Number,
typename Number2,
bool add>
4350 const Number2 &
value,
4355 static_assert(dim >= 0 && dim <= 3,
"Only dim=0,1,2,3 implemented");
4368 const auto x0 = 1. - p[0],
x1 = p[0];
4383 const auto x0 = 1. - p[0],
x1 = p[0],
y0 = 1. - p[1],
y1 = p[1];
4405 const auto x0 = 1. - p[0],
x1 = p[0],
y0 = 1. - p[1],
y1 = p[1],
4406 z0 = 1. - p[2],
z1 = p[2];
4448 template <
int dim,
typename Number,
typename Number2>
4452 const Number2 &
value,
4500 template <
int dim,
int n_po
ints_1d_
template,
typename Number>
4503 const unsigned int n_components,
4520 for (
unsigned int c = 0; c < n_components; ++c)
4524 const unsigned int shift =
4526 data[0] *= weights[shift];
4529 const Number weight = weights[shift + 1];
4538 template <
int dim,
int n_po
ints_1d_
template,
typename Number>
4541 const unsigned int n_components,
4550 ExcMessage(
"The function can only with add number of points"));
4565 for (
unsigned int c = 0; c < n_components; ++c)
4569 const unsigned int shift =
4573 const Number
weight1 = weights[shift];
4576 data[c++] *= weights[shift + 1];
4577 const Number
weight2 = weights[shift + 2];
4585 template <
int dim,
int n_po
ints_1d_
template,
typename Number>
4588 const unsigned int n_components,
4610 const auto check_and_set = [](Number &weight,
const Number &data) {
4611 if (weight == Number(-1.0) || weight == data)
4621 weights[c] = Number(-1.0);
4623 for (
unsigned int c = 0; c < n_components; ++c)
4628 const unsigned int shift =
4646 template <
int dim,
int n_po
ints_1d_
template,
typename Number>
4649 const Number * data,
4650 const unsigned int n_components,
4659 ExcMessage(
"The function can only with add number of points"));
4679 const auto check_and_set = [](Number &weight,
const Number &data) {
4680 if (weight == Number(-1.0) || weight == data)
4690 weights[c] = Number(-1.0);
4692 for (
unsigned int comp = 0;
comp < n_components; ++
comp)
4697 const unsigned int shift =
value_type * data() const noexcept
#define DEAL_II_ALWAYS_INLINE
#define DEAL_II_NAMESPACE_OPEN
#define DEAL_II_NAMESPACE_CLOSE
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcNotInitialized()
static ::ExceptionBase & ExcMessage(std::string arg1)
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
constexpr T pow(const T base, const int iexp)
ProductTypeNoPoint< Number, Number2 >::type evaluate_tensor_product_value(const std::vector< Polynomials::Polynomial< double > > &poly, const std::vector< Number > &values, const Point< dim, Number2 > &p, const bool d_linear=false, const std::vector< unsigned int > &renumber={})
std::array< typename ProductTypeNoPoint< Number, Number2 >::type, dim+n_values > evaluate_tensor_product_value_and_gradient_linear(const unsigned int n_shapes, const Number *values, const Point< dim, Number2 > &p, const std::vector< unsigned int > &renumber={})
void weight_fe_q_dofs_by_entity(const Number *weights, const unsigned int n_components, const int n_points_1d_non_template, Number *data)
void do_apply_test_functions_xy_value(Number2 *values, const ::ndarray< Number, 2, dim > *shapes, const Number2 &test_value, const int n_shapes_runtime, int &i)
void integrate_add_tensor_product_value_shapes(const ::ndarray< Number, 2, dim > *shapes, const int n_shapes, const Number2 &value, Number2 *values)
void even_odd_apply(const int n_rows_in, const int n_columns_in, const Number2 *DEAL_II_RESTRICT shapes, const Number *in, Number *out)
void compute_values_of_array(::ndarray< Number, 2, dim > *shapes, const std::vector< Polynomials::Polynomial< double > > &poly, const Point< dim, Number > &p, const unsigned int derivative=1)
void integrate_add_tensor_product_value_and_gradient_linear(const unsigned int n_shapes, const Number2 *value, const Tensor< 1, dim, Number2 > &gradient, Number2 *values, const Point< dim, Number > &p)
void integrate_add_tensor_product_value_and_gradient_shapes(const ::ndarray< Number, 2, dim > *shapes, const int n_shapes, const Number2 *value, const Tensor< 1, dim, Number2 > &gradient, Number2 *values)
void integrate_tensor_product_value(const ::ndarray< Number, 2, dim > *shapes, const unsigned int n_shapes, const Number2 &value, Number2 *values, const Point< dim, Number > &p, const bool is_linear, const bool do_add)
void weight_fe_q_dofs_by_entity_shifted(const Number *weights, const unsigned int n_components, const int n_points_1d_non_template, Number *data)
ProductTypeNoPoint< Number, Number2 >::type evaluate_tensor_product_value_linear(const unsigned int n_shapes, const Number *values, const Point< dim, Number2 > &p, const std::vector< unsigned int > &renumber={})
void do_apply_test_functions_xy(Number2 *values, const ::ndarray< Number, 2, dim > *shapes, const std::array< Number2, 2+n_values > &test_grads_value, const int n_shapes_runtime, int &i)
ProductTypeNoPoint< Number, Number2 >::type do_interpolate_xy_value(const Number *values, const std::vector< unsigned int > &renumber, const ::ndarray< Number2, 2, dim > *shapes, const int n_shapes_runtime, int &i)
ProductTypeNoPoint< Number, Number2 >::type evaluate_tensor_product_value_shapes(const ::ndarray< Number2, 2, dim > *shapes, const int n_shapes, const Number *values, const std::vector< unsigned int > &renumber={})
Tensor< 1, 1, typename ProductTypeNoPoint< Number, Number2 >::type > evaluate_tensor_product_higher_derivatives(const std::vector< Polynomials::Polynomial< double > > &poly, const std::vector< Number > &values, const Point< 1, Number2 > &p, const std::vector< unsigned int > &renumber={})
bool compute_weights_fe_q_dofs_by_entity(const Number *data, const unsigned int n_components, const int n_points_1d_non_template, Number *weights)
bool compute_weights_fe_q_dofs_by_entity_shifted(const Number *data, const unsigned int n_components, const int n_points_1d_non_template, Number *weights)
std::array< typename ProductTypeNoPoint< Number, Number2 >::type, 2+n_values > do_interpolate_xy(const Number *values, const std::vector< unsigned int > &renumber, const ::ndarray< Number2, 2, dim > *shapes, const int n_shapes_runtime, int &i)
void integrate_add_tensor_product_value_linear(const unsigned int n_shapes, const Number2 &value, Number2 *values, const Point< dim, Number > &p)
std::array< typename ProductTypeNoPoint< Number, Number2 >::type, dim+n_values > evaluate_tensor_product_value_and_gradient_shapes(const ::ndarray< Number2, 2, dim > *shapes, const int n_shapes, const Number *values, const std::vector< unsigned int > &renumber={})
std::pair< typename ProductTypeNoPoint< Number, Number2 >::type, Tensor< 1, dim, typename ProductTypeNoPoint< Number, Number2 >::type > > evaluate_tensor_product_value_and_gradient(const std::vector< Polynomials::Polynomial< double > > &poly, const std::vector< Number > &values, const Point< dim, Number2 > &p, const bool d_linear=false, const std::vector< unsigned int > &renumber={})
@ evaluate_raviart_thomas
@ evaluate_symmetric_hierarchical
void integrate_tensor_product_value_and_gradient(const ::ndarray< Number, 2, dim > *shapes, const unsigned int n_shapes, const Number2 *value, const Tensor< 1, dim, Number2 > &gradient, Number2 *values, const Point< dim, Number > &p, const bool is_linear, const bool do_add)
SymmetricTensor< 2, dim, typename ProductTypeNoPoint< Number, Number2 >::type > evaluate_tensor_product_hessian(const std::vector< Polynomials::Polynomial< double > > &poly, const std::vector< Number > &values, const Point< dim, Number2 > &p, const std::vector< unsigned int > &renumber={})
static const unsigned int invalid_unsigned_int
typename internal::ProductTypeImpl< typename std::decay< T >::type, typename std::decay< U >::type >::type type
void values(const Number in[], Number out[]) const
const Number2 * shape_values
const Number2 * shape_hessians
EvaluatorTensorProductAnisotropic(const AlignedVector< Number2 > &shape_values, const AlignedVector< Number2 > &shape_gradients, const AlignedVector< Number2 > &shape_hessians, const unsigned int dummy1=0, const unsigned int dummy2=0)
const Number2 * shape_gradients
EvaluatorTensorProductAnisotropic()
void gradients(const Number in[], Number out[]) const
void hessians(const Number in[], Number out[]) const
void hessians(const Number in[], Number out[]) const
void gradients_one_line(const Number in[], Number out[]) const
EvaluatorTensorProduct(const AlignedVector< Number2 > &shape_values, const AlignedVector< Number2 > &shape_gradients, const AlignedVector< Number2 > &shape_hessians, const unsigned int n_rows=0, const unsigned int n_columns=0)
const unsigned int n_columns
EvaluatorTensorProduct(const AlignedVector< Number2 > &shape_values, const unsigned int n_rows=0, const unsigned int n_columns=0)
void gradients(const Number in[], Number out[]) const
void hessians_one_line(const Number in[], Number out[]) const
const Number2 * shape_values
void values(const Number in[], Number out[]) const
const Number2 * shape_gradients
const unsigned int n_rows
void values_one_line(const Number in[], Number out[]) const
void apply(const Number2 *DEAL_II_RESTRICT shape_data, const Number *in, Number *out) const
const Number2 * shape_hessians
EvaluatorTensorProduct(const AlignedVector< Number2 > &shape_values, const AlignedVector< Number2 > &shape_gradients, const AlignedVector< Number2 > &shape_hessians, const unsigned int dummy1=0, const unsigned int dummy2=0)
void hessians_one_line(const Number in[], Number out[]) const
EvaluatorTensorProduct(const AlignedVector< Number2 > &shape_values)
void gradients_one_line(const Number in[], Number out[]) const
const Number2 * shape_values
const Number2 * shape_hessians
const Number2 * shape_gradients
void values_one_line(const Number in[], Number out[]) const
static void apply(const Number2 *DEAL_II_RESTRICT shape_data, const Number *in, Number *out)
void values(const Number in[], Number out[]) const
void gradients(const Number in[], Number out[]) const
void hessians(const Number in[], Number out[]) const
EvaluatorTensorProduct(const Number2 *shape_values, const Number2 *shape_gradients, const Number2 *shape_hessians, const unsigned int n_rows, const unsigned int n_columns)
const unsigned int n_columns
const Number2 * shape_gradients
void hessians_one_line(const Number in[], Number out[]) const
void gradients(const Number *in, Number *out) const
void values_one_line(const Number in[], Number out[]) const
void gradients_one_line(const Number in[], Number out[]) const
const Number2 * shape_values
void values(const Number *in, Number *out) const
const Number2 * shape_hessians
EvaluatorTensorProduct(const AlignedVector< Number2 > &shape_values, const AlignedVector< Number2 > &shape_gradients, const AlignedVector< Number2 > &shape_hessians, const unsigned int n_rows, const unsigned int n_columns)
const unsigned int n_rows
void hessians(const Number *in, Number *out) const
void gradients(const Number in[], Number out[]) const
const Number2 * shape_values
EvaluatorTensorProduct(const AlignedVector< Number2 > &shape_values, const AlignedVector< Number2 > &shape_gradients, const AlignedVector< Number2 > &shape_hessians, const unsigned int dummy1=0, const unsigned int dummy2=0)
const Number2 * shape_gradients
void values(const Number in[], Number out[]) const
void hessians(const Number in[], Number out[]) const
void hessians_one_line(const Number in[], Number out[]) const
void values_one_line(const Number in[], Number out[]) const
const Number2 * shape_hessians
EvaluatorTensorProduct(const Number2 *shape_values, const Number2 *shape_gradients, const Number2 *shape_hessians, const unsigned int dummy1=0, const unsigned int dummy2=0)
void gradients_one_line(const Number in[], Number out[]) const
const Number2 * shape_gradients
const Number2 * shape_hessians
EvaluatorTensorProduct(const AlignedVector< Number2 > &shape_values, const AlignedVector< Number2 > &shape_gradients, const AlignedVector< Number2 > &shape_hessians, const unsigned int dummy1=0, const unsigned int dummy2=0)
const Number2 * shape_values
const Number2 * shape_hessians
void gradients(const Number in[], Number out[]) const
void values(const Number in[], Number out[]) const
void hessians_one_line(const Number in[], Number out[]) const
EvaluatorTensorProduct(const AlignedVector< Number > &shape_values)
void values_one_line(const Number in[], Number out[]) const
EvaluatorTensorProduct(const AlignedVector< Number2 > &shape_values, const AlignedVector< Number2 > &shape_gradients, const AlignedVector< Number2 > &shape_hessians, const unsigned int dummy1=0, const unsigned int dummy2=0)
void gradients_one_line(const Number in[], Number out[]) const
void hessians(const Number in[], Number out[]) const
const Number2 * shape_gradients
const Number2 * shape_values
typename ProductType< Tensor< 1, dim, Number >, Number2 >::type type
typename ProductType< Number, Number2 >::type type