19 template <
int p,
int c>
20 struct finite_element<mfem::Geometry::SEGMENT, H1<p, c> > {
21 static constexpr
auto geometry = mfem::Geometry::SEGMENT;
22 static constexpr
auto family = Family::H1;
23 static constexpr
int components = c;
24 static constexpr
int dim = 1;
25 static constexpr
int n = (p + 1);
26 static constexpr
int ndof = (p + 1);
28 static constexpr
int VALUE = 0, GRADIENT = 1;
29 static constexpr
int SOURCE = 0, FLUX = 1;
31 using dof_type = tensor<double, c, n>;
32 using dof_type_if = dof_type;
34 using value_type =
typename std::conditional<components == 1, double, tensor<double, components> >
::type;
35 using derivative_type = value_type;
36 using qf_input_type = tuple<value_type, derivative_type>;
39 typename std::conditional<components == 1, tensor<double, ndof>, tensor<double, ndof, components> >
::type;
41 SMITH_HOST_DEVICE static constexpr tensor<double, ndof> shape_functions(
double xi)
43 return GaussLobattoInterpolation<ndof>(xi);
46 SMITH_HOST_DEVICE static constexpr tensor<double, ndof> shape_function_gradients(
double xi)
48 return GaussLobattoInterpolationDerivative<ndof>(xi);
61 template <
bool apply_weights,
int q>
62 static constexpr
auto calculate_B()
64 constexpr
auto points1D = GaussLegendreNodes<q, mfem::Geometry::SEGMENT>();
65 [[maybe_unused]] constexpr
auto weights1D = GaussLegendreWeights<q, mfem::Geometry::SEGMENT>();
66 tensor<double, q, n> B{};
67 for (
int i = 0; i < q; i++) {
68 B[i] = GaussLobattoInterpolation<n>(points1D[i]);
69 if constexpr (apply_weights) B[i] = B[i] * weights1D[i];
84 template <
bool apply_weights,
int q>
85 static constexpr
auto calculate_G()
87 constexpr
auto points1D = GaussLegendreNodes<q, mfem::Geometry::SEGMENT>();
88 [[maybe_unused]] constexpr
auto weights1D = GaussLegendreWeights<q, mfem::Geometry::SEGMENT>();
89 tensor<double, q, n> G{};
90 for (
int i = 0; i < q; i++) {
91 G[i] = GaussLobattoInterpolationDerivative<n>(points1D[i]);
92 if constexpr (apply_weights) G[i] = G[i] * weights1D[i];
97 template <
typename T,
int q>
98 SMITH_HOST_DEVICE static auto batch_apply_shape_fn(
int jx, tensor<T, q> input,
const TensorProductQuadratureRule<q>&)
100 static constexpr
bool apply_weights =
false;
101 static constexpr
auto B = calculate_B<apply_weights, q>();
102 static constexpr
auto G = calculate_G<apply_weights, q>();
104 using source_t = decltype(get<0>(get<0>(T{})) + get<1>(get<0>(T{})));
105 using flux_t = decltype(get<0>(get<1>(T{})) + get<1>(get<1>(T{})));
107 tensor<tuple<source_t, flux_t>, q> output;
109 for (
int qx = 0; qx < q; qx++) {
110 double phi_j = B(qx, jx);
111 double dphi_j_dxi = G(qx, jx);
113 const auto& d00 = get<0>(get<0>(input(qx)));
114 const auto& d01 = get<1>(get<0>(input(qx)));
115 const auto& d10 = get<0>(get<1>(input(qx)));
116 const auto& d11 = get<1>(get<1>(input(qx)));
118 output[qx] = {d00 * phi_j + d01 * dphi_j_dxi, d10 * phi_j + d11 * dphi_j_dxi};
125 SMITH_HOST_DEVICE static auto interpolate(
const dof_type& X,
const TensorProductQuadratureRule<q>&)
127 static constexpr
bool apply_weights =
false;
128 static constexpr
auto B = calculate_B<apply_weights, q>();
129 static constexpr
auto G = calculate_G<apply_weights, q>();
131 tensor<double, c, q> value{};
132 tensor<double, c, q> gradient{};
135 for (
int i = 0; i < c; i++) {
136 value(i) =
dot(B, X[i]);
137 gradient(i) =
dot(G, X[i]);
141 tensor<qf_input_type, q> output;
143 for (
int qx = 0; qx < q; qx++) {
144 if constexpr (c == 1) {
145 get<VALUE>(output(qx)) = value(0, qx);
146 get<GRADIENT>(output(qx)) = gradient(0, qx);
148 for (
int i = 0; i < c; i++) {
149 get<VALUE>(output(qx))[i] = value(i, qx);
150 get<GRADIENT>(output(qx))[i] = gradient(i, qx);
158 template <
typename source_type,
typename flux_type,
int q>
160 const TensorProductQuadratureRule<q>&, dof_type* element_residual,
161 [[maybe_unused]]
int step = 1)
163 if constexpr (is_zero<source_type>{} && is_zero<flux_type>{}) {
167 constexpr
int ntrial =
std::max(
size(source_type{}),
size(flux_type{}) / dim) / c;
169 using s_buffer_type = std::conditional_t<is_zero<source_type>{}, zero, tensor<double, q> >;
170 using f_buffer_type = std::conditional_t<is_zero<flux_type>{}, zero, tensor<double, q> >;
172 static constexpr
bool apply_weights =
true;
173 static constexpr
auto B = calculate_B<apply_weights, q>();
174 static constexpr
auto G = calculate_G<apply_weights, q>();
176 for (
int j = 0; j < ntrial; j++) {
177 for (
int i = 0; i < c; i++) {
178 s_buffer_type source;
181 for (
int qx = 0; qx < q; qx++) {
182 if constexpr (!is_zero<source_type>{}) {
183 source(qx) =
reinterpret_cast<const double*
>(&get<SOURCE>(qf_output[qx]))[i * ntrial + j];
185 if constexpr (!is_zero<flux_type>{}) {
186 flux(qx) =
reinterpret_cast<const double*
>(&get<FLUX>(qf_output[qx]))[i * ntrial + j];
190 element_residual[j * step](i) +=
dot(source, B) +
dot(flux, G);
#define SMITH_HOST_DEVICE
Macro that evaluates to __host__ __device__ when compiling with nvcc and does nothing on a host compi...
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