22 template <
int p,
int c>
23 struct finite_element<mfem::Geometry::TETRAHEDRON, H1<p, c> > {
24 static constexpr
auto geometry = mfem::Geometry::TETRAHEDRON;
25 static constexpr
auto family = Family::H1;
26 static constexpr
int components = c;
27 static constexpr
int dim = 3;
28 static constexpr
int n = (p + 1);
29 static constexpr
int ndof = (p + 1) * (p + 2) * (p + 3) / 6;
30 static constexpr
int order = p;
33 static constexpr
int VALUE = 0, GRADIENT = 1;
34 static constexpr
int SOURCE = 0, FLUX = 1;
37 typename std::conditional<components == 1, tensor<double, ndof>, tensor<double, ndof, components> >
::type;
39 using dof_type = tensor<double, c, ndof>;
41 using value_type =
typename std::conditional<components == 1, double, tensor<double, components> >
::type;
42 using derivative_type =
43 typename std::conditional<components == 1, tensor<double, dim>, tensor<double, components, dim> >
::type;
44 using qf_input_type = tuple<value_type, derivative_type>;
46 SMITH_HOST_DEVICE static constexpr
double shape_function([[maybe_unused]] tensor<double, dim> xi,
int i)
48 if constexpr (p == 1) {
51 return 1 - xi[0] - xi[1] - xi[2];
60 if constexpr (p == 2) {
63 return (-1 + xi[0] + xi[1] + xi[2]) * (-1 + 2 * xi[0] + 2 * xi[1] + 2 * xi[2]);
65 return -4 * xi[0] * (-1 + xi[0] + xi[1] + xi[2]);
67 return xi[0] * (-1 + 2 * xi[0]);
69 return -4 * xi[1] * (-1 + xi[0] + xi[1] + xi[2]);
71 return 4 * xi[0] * xi[1];
73 return xi[1] * (-1 + 2 * xi[1]);
75 return -4 * xi[2] * (-1 + xi[0] + xi[1] + xi[2]);
77 return 4 * xi[0] * xi[2];
79 return 4 * xi[1] * xi[2];
81 return xi[2] * (-1 + 2 * xi[2]);
85 if constexpr (p == 3) {
86 constexpr
double sqrt5 = 2.23606797749978981;
89 return -((-1 + xi[0] + xi[1] + xi[2]) *
90 (1 + 5 * xi[0] * xi[0] + 5 * xi[1] * xi[1] + 5 * (-1 + xi[2]) * xi[2] + xi[1] * (-5 + 11 * xi[2]) +
91 xi[0] * (-5 + 11 * xi[1] + 11 * xi[2])));
93 return (5 * xi[0] * (-1 + xi[0] + xi[1] + xi[2]) *
94 (-1 - sqrt5 + 2 * sqrt5 * xi[0] + (3 + sqrt5) * xi[1] + (3 + sqrt5) * xi[2])) /
97 return (-5 * xi[0] * (-1 + xi[0] + xi[1] + xi[2]) *
98 (1 - sqrt5 + 2 * sqrt5 * xi[0] + (-3 + sqrt5) * xi[1] + (-3 + sqrt5) * xi[2])) /
101 return xi[0] * (1 + 5 * xi[0] * xi[0] + xi[1] - xi[1] * xi[1] + xi[2] - xi[1] * xi[2] - xi[2] * xi[2] -
102 xi[0] * (5 + xi[1] + xi[2]));
104 return (5 * xi[1] * (-1 + xi[0] + xi[1] + xi[2]) *
105 (-1 - sqrt5 + (3 + sqrt5) * xi[0] + 2 * sqrt5 * xi[1] + (3 + sqrt5) * xi[2])) /
108 return -27 * xi[0] * xi[1] * (-1 + xi[0] + xi[1] + xi[2]);
110 return (5 * xi[0] * xi[1] * (-2 + (3 + sqrt5) * xi[0] - (-3 + sqrt5) * xi[1])) / 2.;
112 return (-5 * xi[1] * (-1 + xi[0] + xi[1] + xi[2]) *
113 (1 - sqrt5 + (-3 + sqrt5) * xi[0] + 2 * sqrt5 * xi[1] + (-3 + sqrt5) * xi[2])) /
116 return (-5 * xi[0] * xi[1] * (2 + (-3 + sqrt5) * xi[0] - (3 + sqrt5) * xi[1])) / 2.;
118 return xi[1] * (1 - xi[0] * xi[0] + 5 * xi[1] * xi[1] + xi[2] - xi[2] * xi[2] - xi[1] * (5 + xi[2]) -
119 xi[0] * (-1 + xi[1] + xi[2]));
121 return (5 * xi[2] * (-1 + xi[0] + xi[1] + xi[2]) *
122 (-439204 - 196418 * sqrt5 + (710647 + 317811 * sqrt5) * xi[0] + (710647 + 317811 * sqrt5) * xi[1] +
123 606965 * xi[2] + 271443 * sqrt5 * xi[2])) /
124 (271443 + 121393 * sqrt5);
126 return -27 * xi[0] * xi[2] * (-1 + xi[0] + xi[1] + xi[2]);
128 return (5 * xi[0] * xi[2] * (-5 - 3 * sqrt5 + (15 + 7 * sqrt5) * xi[0] + 2 * sqrt5 * xi[2])) /
131 return -27 * xi[1] * xi[2] * (-1 + xi[0] + xi[1] + xi[2]);
133 return 27 * xi[0] * xi[1] * xi[2];
135 return (5 * xi[1] * xi[2] * (-5 - 3 * sqrt5 + (15 + 7 * sqrt5) * xi[1] + 2 * sqrt5 * xi[2])) /
138 return (5 * xi[2] * (-1 + xi[0] + xi[1] + xi[2]) *
139 (88555 + 39603 * sqrt5 + (54730 + 24476 * sqrt5) * xi[0] + (54730 + 24476 * sqrt5) * xi[1] -
140 5 * (64079 + 28657 * sqrt5) * xi[2])) /
141 (143285 + 64079 * sqrt5);
143 return (-5 * xi[0] * xi[2] * (2 + (-3 + sqrt5) * xi[0] - (3 + sqrt5) * xi[2])) / 2.;
145 return (-5 * xi[1] * xi[2] * (2 + (-3 + sqrt5) * xi[1] - (3 + sqrt5) * xi[2])) / 2.;
147 return -(xi[2] * (-1 + xi[0] * xi[0] + xi[1] * xi[1] + xi[1] * (-1 + xi[2]) - 5 * (-1 + xi[2]) * xi[2] +
148 xi[0] * (-1 + xi[1] + xi[2])));
156 [[maybe_unused]] tensor<double, dim> xi,
int i)
173 return {-3 + 4 * xi[0] + 4 * xi[1] + 4 * xi[2], -3 + 4 * xi[0] + 4 * xi[1] + 4 * xi[2],
174 -3 + 4 * xi[0] + 4 * xi[1] + 4 * xi[2]};
176 return {-4 * (-1 + 2 * xi[0] + xi[1] + xi[2]), -4 * xi[0], -4 * xi[0]};
178 return {-1 + 4 * xi[0], 0, 0};
180 return {-4 * xi[1], -4 * (-1 + xi[0] + 2 * xi[1] + xi[2]), -4 * xi[1]};
182 return {4 * xi[1], 4 * xi[0], 0};
184 return {0, -1 + 4 * xi[1], 0};
186 return {-4 * xi[2], -4 * xi[2], -4 * (-1 + xi[0] + xi[1] + 2 * xi[2])};
188 return {4 * xi[2], 0, 4 * xi[0]};
190 return {0, 4 * xi[2], 4 * xi[1]};
192 return {0, 0, -1 + 4 * xi[2]};
197 constexpr
double sqrt5 = 2.23606797749978981;
200 return {-6 - 15 * xi[0] * xi[0] - 16 * xi[1] * xi[1] + xi[1] * (21 - 33 * xi[2]) + (21 - 16 * xi[2]) * xi[2] -
201 4 * xi[0] * (-5 + 8 * xi[1] + 8 * xi[2]),
202 -6 - 16 * xi[0] * xi[0] + 20 * xi[1] + xi[0] * (21 - 32 * xi[1] - 33 * xi[2]) + 21 * xi[2] -
203 (3 * xi[1] + 4 * xi[2]) * (5 * xi[1] + 4 * xi[2]),
204 -6 - 16 * xi[0] * xi[0] + 21 * xi[1] + xi[0] * (21 - 33 * xi[1] - 32 * xi[2]) + 20 * xi[2] -
205 (4 * xi[1] + 3 * xi[2]) * (4 * xi[1] + 5 * xi[2])};
207 return {(5 * (6 * sqrt5 * xi[0] * xi[0] +
208 xi[0] * (-2 - 6 * sqrt5 + 6 * (1 + sqrt5) * xi[1] + 6 * (1 + sqrt5) * xi[2]) +
209 (-1 + xi[1] + xi[2]) * (-1 - sqrt5 + (3 + sqrt5) * xi[1] + (3 + sqrt5) * xi[2]))) /
212 (-4 - 2 * sqrt5 + 3 * (1 + sqrt5) * xi[0] + 2 * (3 + sqrt5) * xi[1] + 2 * (3 + sqrt5) * xi[2])) /
215 (-4 - 2 * sqrt5 + 3 * (1 + sqrt5) * xi[0] + 2 * (3 + sqrt5) * xi[1] + 2 * (3 + sqrt5) * xi[2])) /
218 return {-15 * sqrt5 * xi[0] * xi[0] -
219 (5 * (-1 + xi[1] + xi[2]) * (1 - sqrt5 + (-3 + sqrt5) * xi[1] + (-3 + sqrt5) * xi[2])) / 2. -
220 5 * xi[0] * (1 - 3 * sqrt5 + 3 * (-1 + sqrt5) * xi[1] + 3 * (-1 + sqrt5) * xi[2]),
222 (4 - 2 * sqrt5 + 3 * (-1 + sqrt5) * xi[0] + 2 * (-3 + sqrt5) * xi[1] + 2 * (-3 + sqrt5) * xi[2])) /
225 (4 - 2 * sqrt5 + 3 * (-1 + sqrt5) * xi[0] + 2 * (-3 + sqrt5) * xi[1] + 2 * (-3 + sqrt5) * xi[2])) /
228 return {1 + 15 * xi[0] * xi[0] + xi[1] - xi[1] * xi[1] + xi[2] - xi[1] * xi[2] - xi[2] * xi[2] -
229 2 * xi[0] * (5 + xi[1] + xi[2]),
230 -(xi[0] * (-1 + xi[0] + 2 * xi[1] + xi[2])), -(xi[0] * (-1 + xi[0] + xi[1] + 2 * xi[2]))};
233 (-2 * (2 + sqrt5) + 2 * (3 + sqrt5) * xi[0] + 3 * (1 + sqrt5) * xi[1] + 2 * (3 + sqrt5) * xi[2])) /
235 15 * sqrt5 * xi[1] * xi[1] +
236 5 * xi[1] * (-1 - 3 * sqrt5 + 3 * (1 + sqrt5) * xi[0] + 3 * (1 + sqrt5) * xi[2]) +
237 (5 * (-1 + xi[0] + xi[2]) * (-1 - sqrt5 + (3 + sqrt5) * xi[0] + (3 + sqrt5) * xi[2])) / 2.,
239 (-2 * (2 + sqrt5) + 2 * (3 + sqrt5) * xi[0] + 3 * (1 + sqrt5) * xi[1] + 2 * (3 + sqrt5) * xi[2])) /
242 return {-27 * xi[1] * (-1 + 2 * xi[0] + xi[1] + xi[2]), -27 * xi[0] * (-1 + xi[0] + 2 * xi[1] + xi[2]),
243 -27 * xi[0] * xi[1]};
245 return {(-5 * xi[1] * (2 - 2 * (3 + sqrt5) * xi[0] + (-3 + sqrt5) * xi[1])) / 2.,
246 (5 * xi[0] * (-2 + (3 + sqrt5) * xi[0] - 2 * (-3 + sqrt5) * xi[1])) / 2., 0};
248 return {(-5 * xi[1] *
249 (4 - 2 * sqrt5 + 2 * (-3 + sqrt5) * xi[0] + 3 * (-1 + sqrt5) * xi[1] + 2 * (-3 + sqrt5) * xi[2])) /
251 -15 * sqrt5 * xi[1] * xi[1] -
252 (5 * (-1 + xi[0] + xi[2]) * (1 - sqrt5 + (-3 + sqrt5) * xi[0] + (-3 + sqrt5) * xi[2])) / 2. -
253 5 * xi[1] * (1 - 3 * sqrt5 + 3 * (-1 + sqrt5) * xi[0] + 3 * (-1 + sqrt5) * xi[2]),
255 (4 - 2 * sqrt5 + 2 * (-3 + sqrt5) * xi[0] + 3 * (-1 + sqrt5) * xi[1] + 2 * (-3 + sqrt5) * xi[2])) /
258 return {(5 * xi[1] * (-2 - 2 * (-3 + sqrt5) * xi[0] + (3 + sqrt5) * xi[1])) / 2.,
259 (-5 * xi[0] * (2 + (-3 + sqrt5) * xi[0] - 2 * (3 + sqrt5) * xi[1])) / 2., 0};
261 return {-(xi[1] * (-1 + 2 * xi[0] + xi[1] + xi[2])),
262 1 - xi[0] * xi[0] + 15 * xi[1] * xi[1] + xi[2] - xi[2] * xi[2] - 2 * xi[1] * (5 + xi[2]) -
263 xi[0] * (-1 + 2 * xi[1] + xi[2]),
264 -(xi[1] * (-1 + xi[0] + xi[1] + 2 * xi[2]))};
268 (-2 * (2 + sqrt5) + 2 * (3 + sqrt5) * xi[0] + 2 * (3 + sqrt5) * xi[1] + 3 * (1 + sqrt5) * xi[2])) /
271 (-2 * (2 + sqrt5) + 2 * (3 + sqrt5) * xi[0] + 2 * (3 + sqrt5) * xi[1] + 3 * (1 + sqrt5) * xi[2])) /
273 (5 * (1 + sqrt5 + (3 + sqrt5) * xi[0] * xi[0] - 2 * (2 + sqrt5) * xi[1] + (3 + sqrt5) * xi[1] * xi[1] +
274 6 * (1 + sqrt5) * xi[1] * xi[2] + 2 * xi[2] * (-1 - 3 * sqrt5 + 3 * sqrt5 * xi[2]) +
275 2 * xi[0] * (-2 - sqrt5 + (3 + sqrt5) * xi[1] + 3 * (1 + sqrt5) * xi[2]))) /
278 return {-27 * xi[2] * (-1 + 2 * xi[0] + xi[1] + xi[2]), -27 * xi[0] * xi[2],
279 -27 * xi[0] * (-1 + xi[0] + xi[1] + 2 * xi[2])};
281 return {(-5 * xi[2] * (2 - 2 * (3 + sqrt5) * xi[0] + (-3 + sqrt5) * xi[2])) / 2., 0,
282 (5 * xi[0] * (-2 + (3 + sqrt5) * xi[0] - 2 * (-3 + sqrt5) * xi[2])) / 2.};
284 return {-27 * xi[1] * xi[2], -27 * xi[2] * (-1 + xi[0] + 2 * xi[1] + xi[2]),
285 -27 * xi[1] * (-1 + xi[0] + xi[1] + 2 * xi[2])};
287 return {27 * xi[1] * xi[2], 27 * xi[0] * xi[2], 27 * xi[0] * xi[1]};
289 return {0, (-5 * xi[2] * (2 - 2 * (3 + sqrt5) * xi[1] + (-3 + sqrt5) * xi[2])) / 2.,
290 (5 * xi[1] * (-2 + (3 + sqrt5) * xi[1] - 2 * (-3 + sqrt5) * xi[2])) / 2.};
294 (4 - 2 * sqrt5 + 2 * (-3 + sqrt5) * xi[0] + 2 * (-3 + sqrt5) * xi[1] + 3 * (-1 + sqrt5) * xi[2])) /
297 (4 - 2 * sqrt5 + 2 * (-3 + sqrt5) * xi[0] + 2 * (-3 + sqrt5) * xi[1] + 3 * (-1 + sqrt5) * xi[2])) /
299 (-5 * (-3 + sqrt5) * xi[0] * xi[0]) / 2. -
300 5 * xi[0] * (2 - sqrt5 + (-3 + sqrt5) * xi[1] + 3 * (-1 + sqrt5) * xi[2]) -
301 (5 * (-1 + sqrt5 + (-3 + sqrt5) * xi[1] * xi[1] + 2 * xi[2] * (1 - 3 * sqrt5 + 3 * sqrt5 * xi[2]) +
302 xi[1] * (4 - 2 * sqrt5 + 6 * (-1 + sqrt5) * xi[2]))) /
305 return {(5 * xi[2] * (-2 - 2 * (-3 + sqrt5) * xi[0] + (3 + sqrt5) * xi[2])) / 2., 0,
306 (-5 * xi[0] * (2 + (-3 + sqrt5) * xi[0] - 2 * (3 + sqrt5) * xi[2])) / 2.};
308 return {0, (5 * xi[2] * (-2 - 2 * (-3 + sqrt5) * xi[1] + (3 + sqrt5) * xi[2])) / 2.,
309 (-5 * xi[1] * (2 + (-3 + sqrt5) * xi[1] - 2 * (3 + sqrt5) * xi[2])) / 2.};
311 return {-(xi[2] * (-1 + 2 * xi[0] + xi[1] + xi[2])), -(xi[2] * (-1 + xi[0] + 2 * xi[1] + xi[2])),
312 1 + xi[0] - xi[0] * xi[0] + xi[1] - xi[0] * xi[1] - xi[1] * xi[1] - 2 * (5 + xi[0] + xi[1]) * xi[2] +
320 SMITH_HOST_DEVICE static constexpr tensor<double, ndof> shape_functions(tensor<double, dim> xi)
322 tensor<double, ndof> output{};
323 for (
int i = 0; i < ndof; i++) {
324 output[i] = shape_function(xi, i);
329 SMITH_HOST_DEVICE static constexpr tensor<double, ndof, dim> shape_function_gradients(tensor<double, dim> xi)
331 tensor<double, ndof, dim> output{};
332 for (
int i = 0; i < ndof; i++) {
333 output[i] = shape_function_gradient(xi, i);
338 template <
typename in_t,
int q>
339 static auto batch_apply_shape_fn(
int j,
tensor<in_t, nqpts(q)> input,
const TensorProductQuadratureRule<q>&)
341 using source_t = decltype(get<0>(get<0>(in_t{})) +
dot(get<1>(get<0>(in_t{})), tensor<double, dim>{}));
342 using flux_t = decltype(get<0>(get<1>(in_t{})) +
dot(get<1>(get<1>(in_t{})), tensor<double, dim>{}));
344 constexpr
auto xi = GaussLegendreNodes<q, mfem::Geometry::TETRAHEDRON>();
346 tensor<tuple<source_t, flux_t>, nqpts(q)> output;
348 for (
int i = 0; i < nqpts(q); i++) {
349 double phi_j = shape_function(xi[i], j);
350 tensor<double, dim> dphi_j_dxi = shape_function_gradient(xi[i], j);
352 const auto& d00 = get<0>(get<0>(input(i)));
353 const auto& d01 = get<1>(get<0>(input(i)));
354 const auto& d10 = get<0>(get<1>(input(i)));
355 const auto& d11 = get<1>(get<1>(input(i)));
357 output[i] = {d00 * phi_j +
dot(d01, dphi_j_dxi), d10 * phi_j +
dot(d11, dphi_j_dxi)};
364 SMITH_HOST_DEVICE static auto interpolate(
const tensor<double, c, ndof>& X,
const TensorProductQuadratureRule<q>&)
366 constexpr
auto xi = GaussLegendreNodes<q, mfem::Geometry::TETRAHEDRON>();
370 tensor<tuple<tensor<double, c>, tensor<double, c, dim> >, nqpts(q)> unflattened;
371 tensor<qf_input_type, nqpts(q)> flattened;
374 for (
int i = 0; i < c; i++) {
375 for (
int j = 0; j < nqpts(q); j++) {
376 for (
int k = 0; k < ndof; k++) {
377 get<VALUE>(output.unflattened[j])[i] += X(i, k) * shape_function(xi[j], k);
378 get<GRADIENT>(output.unflattened[j])[i] += X(i, k) * shape_function_gradient(xi[j], k);
383 return output.flattened;
386 template <
typename source_type,
typename flux_type,
int q>
388 const TensorProductQuadratureRule<q>&,
389 tensor<double, c, ndof>* element_residual,
int step = 1)
391 if constexpr (is_zero<source_type>{} && is_zero<flux_type>{}) {
395 using source_component_type = std::conditional_t<is_zero<source_type>{}, zero,
double>;
396 using flux_component_type = std::conditional_t<is_zero<flux_type>{}, zero, tensor<double, dim> >;
398 constexpr
int ntrial =
std::max(
size(source_type{}),
size(flux_type{}) / dim) / c;
399 constexpr
auto integration_points = GaussLegendreNodes<q, mfem::Geometry::TETRAHEDRON>();
400 constexpr
auto integration_weights = GaussLegendreWeights<q, mfem::Geometry::TETRAHEDRON>();
402 for (
int j = 0; j < ntrial; j++) {
403 for (
int i = 0; i < c; i++) {
404 for (
int Q = 0; Q < nqpts(q); Q++) {
405 tensor<double, dim> xi = integration_points[Q];
406 double wt = integration_weights[Q];
408 source_component_type source;
409 if constexpr (!is_zero<source_type>{}) {
410 source =
reinterpret_cast<const double*
>(&get<SOURCE>(qf_output[Q]))[i * ntrial + j];
413 flux_component_type flux;
414 if constexpr (!is_zero<flux_type>{}) {
415 for (
int k = 0; k < dim; k++) {
416 flux[k] =
reinterpret_cast<const double*
>(&get<FLUX>(qf_output[Q]))[(i * dim + k) * ntrial + j];
420 for (
int k = 0; k < ndof; k++) {
421 element_residual[j * step](i, k) +=
422 (source * shape_function(xi, k) +
dot(flux, shape_function_gradient(xi, k))) * wt;
#define SMITH_HOST_DEVICE
Macro that evaluates to __host__ __device__ when compiling with nvcc and does nothing on a host compi...
constexpr int num_quadrature_points(mfem::Geometry::Type g, int Q)
return the number of quadrature points in a Gauss-Legendre rule with parameter "Q"
constexpr SMITH_HOST_DEVICE auto type(const tuple< T... > &values)
a function intended to be used for extracting the ith type from a tuple.
SMITH_HOST_DEVICE auto max(dual< gradient_type > a, double b)
Implementation of max for dual numbers.
constexpr SMITH_HOST_DEVICE int size(const tensor< T, n... > &)
returns the total number of stored values in a tensor
tensor(const T(&data)[n1]) -> tensor< T, n1 >
class template argument deduction guide for type tensor.
constexpr SMITH_HOST_DEVICE auto dot(const isotropic_tensor< S, m, m > &I, const tensor< T, m, n... > &A)
dot product between an isotropic and (nonisotropic) tensor