19 template <
int p,
int c>
20 struct finite_element<mfem::Geometry::SEGMENT, L2<p, c> > {
21 static constexpr
auto geometry = mfem::Geometry::SEGMENT;
22 static constexpr
auto family = Family::L2;
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 = tensor<double, c, 2, ndof>;
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 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 auto& d00 = get<0>(get<0>(input(qx)));
114 auto& d01 = get<1>(get<0>(input(qx)));
115 auto& d10 = get<0>(get<1>(input(qx)));
116 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};
124 template <
typename T,
int q>
125 static auto batch_apply_shape_fn_interior_face(
int jx, tensor<T, q> input,
const TensorProductQuadratureRule<q>&)
127 static constexpr
bool apply_weights =
false;
128 static constexpr
auto B = calculate_B<apply_weights, q>();
130 using source0_t = decltype(get<0>(get<0>(T{})) + get<1>(get<0>(T{})));
131 using source1_t = decltype(get<0>(get<1>(T{})) + get<1>(get<1>(T{})));
133 tensor<tuple<source0_t, source1_t>, q> output;
135 for (
int qx = 0; qx < q; qx++) {
139 double phi0_j = B(qx, j) * (s == 0);
140 double phi1_j = B(qx, j) * (s == 1);
142 const auto& d00 = get<0>(get<0>(input(qx)));
143 const auto& d01 = get<1>(get<0>(input(qx)));
144 const auto& d10 = get<0>(get<1>(input(qx)));
145 const auto& d11 = get<1>(get<1>(input(qx)));
147 output[qx] = {d00 * phi0_j + d01 * phi1_j, d10 * phi0_j + d11 * phi1_j};
154 SMITH_HOST_DEVICE static auto interpolate(
const dof_type_if& X,
const TensorProductQuadratureRule<q>&)
156 static constexpr
bool apply_weights =
false;
157 static constexpr
auto BT =
transpose(calculate_B<apply_weights, q>());
159 tensor<double, q> values{};
161 tensor<tuple<value_type, value_type>, q> output{};
164 for (
int i = 0; i < c; i++) {
165 values =
dot(X[i][0], BT);
166 for (
int qx = 0; qx < q; qx++) {
167 if constexpr (c == 1) {
168 get<0>(output[qx]) = values[qx];
170 get<0>(output[qx])[i] = values[qx];
174 values =
dot(X[i][1], BT);
175 for (
int qx = 0; qx < q; qx++) {
176 if constexpr (c == 1) {
177 get<1>(output[qx]) = values[qx];
179 get<1>(output[qx])[i] = values[qx];
188 SMITH_HOST_DEVICE static auto interpolate(
const dof_type& X,
const TensorProductQuadratureRule<q>&)
190 static constexpr
bool apply_weights =
false;
191 static constexpr
auto B = calculate_B<apply_weights, q>();
192 static constexpr
auto G = calculate_G<apply_weights, q>();
194 tensor<double, c, q> value{};
195 tensor<double, c, q> gradient{};
198 for (
int i = 0; i < c; i++) {
199 value(i) =
dot(B, X[i]);
200 gradient(i) =
dot(G, X[i]);
204 tensor<qf_input_type, q> output;
206 for (
int qx = 0; qx < q; qx++) {
207 if constexpr (c == 1) {
208 get<VALUE>(output(qx)) = value(0, qx);
209 get<GRADIENT>(output(qx)) = gradient(0, qx);
211 for (
int i = 0; i < c; i++) {
212 get<VALUE>(output(qx))[i] = value(i, qx);
213 get<GRADIENT>(output(qx))[i] = gradient(i, qx);
221 template <
typename source_type,
typename flux_type,
int q>
223 const TensorProductQuadratureRule<q>&, dof_type* element_residual,
224 [[maybe_unused]]
int step = 1)
226 if constexpr (is_zero<source_type>{} && is_zero<flux_type>{}) {
230 constexpr
int ntrial =
std::max(
size(source_type{}),
size(flux_type{}) / dim) / c;
232 using s_buffer_type = std::conditional_t<is_zero<source_type>{}, zero, tensor<double, q> >;
233 using f_buffer_type = std::conditional_t<is_zero<flux_type>{}, zero, tensor<double, q> >;
235 static constexpr
bool apply_weights =
true;
236 static constexpr
auto B = calculate_B<apply_weights, q>();
237 static constexpr
auto G = calculate_G<apply_weights, q>();
239 for (
int j = 0; j < ntrial; j++) {
240 for (
int i = 0; i < c; i++) {
241 s_buffer_type source;
244 for (
int qx = 0; qx < q; qx++) {
245 if constexpr (!is_zero<source_type>{}) {
246 source(qx) =
reinterpret_cast<const double*
>(&get<SOURCE>(qf_output[qx]))[i * ntrial + j];
248 if constexpr (!is_zero<flux_type>{}) {
249 flux(qx) =
reinterpret_cast<const double*
>(&get<FLUX>(qf_output[qx]))[i * ntrial + j];
253 element_residual[j * step](i) +=
dot(source, B) +
dot(flux, G);
258 template <
typename T,
int q>
260 const TensorProductQuadratureRule<q>&, dof_type_if* element_residual,
261 [[maybe_unused]]
int step = 1)
263 constexpr
int ntrial =
size(T{}) / c;
265 using buffer_type = tensor<double, q>;
267 static constexpr
bool apply_weights =
true;
268 static constexpr
auto B = calculate_B<apply_weights, q>();
270 for (
int j = 0; j < ntrial; j++) {
271 for (
int i = 0; i < c; i++) {
272 buffer_type source_0;
273 buffer_type source_1;
275 for (
int qx = 0; qx < q; qx++) {
276 source_0(qx) =
reinterpret_cast<const double*
>(&get<0>(qf_output[qx]))[i * ntrial + j];
277 source_1(qx) =
reinterpret_cast<const double*
>(&get<1>(qf_output[qx]))[i * ntrial + j];
280 element_residual[j * step](i, 0) +=
dot(source_0, B);
281 element_residual[j * step](i, 1) +=
dot(source_1, B);
#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
constexpr SMITH_HOST_DEVICE auto transpose(const isotropic_tensor< T, m, m > &I)
return the transpose of an isotropic 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