Smith  0.1
Smith is an implicit thermal structural mechanics simulation code.
segment_L2.inl
Go to the documentation of this file.
1 // Copyright (c) Lawrence Livermore National Security, LLC and
2 // other Smith Project Developers. See the top-level LICENSE file for
3 // details.
4 //
5 // SPDX-License-Identifier: (BSD-3-Clause)
6 
13 // this specialization defines shape functions (and their gradients) that
14 // interpolate at Gauss-Lobatto nodes for the appropriate polynomial order
15 //
16 // note: mfem assumes the parent element domain is [0,1]
17 // for additional information on the finite_element concept requirements, see finite_element.hpp
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);
27 
28  static constexpr int VALUE = 0, GRADIENT = 1;
29  static constexpr int SOURCE = 0, FLUX = 1;
30 
31  using dof_type = tensor<double, c, n>;
32  using dof_type_if = tensor<double, c, 2, ndof>;
33 
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>;
37 
38  using residual_type =
39  typename std::conditional<components == 1, tensor<double, ndof>, tensor<double, ndof, components> >::type;
40 
41  SMITH_HOST_DEVICE static constexpr tensor<double, ndof> shape_functions(double xi)
42  {
43  return GaussLobattoInterpolation<ndof>(xi);
44  }
45 
46  SMITH_HOST_DEVICE static constexpr tensor<double, ndof> shape_function_gradients(double xi)
47  {
48  return GaussLobattoInterpolationDerivative<ndof>(xi);
49  }
50 
61  template <bool apply_weights, int q>
62  static constexpr auto calculate_B()
63  {
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];
70  }
71  return B;
72  }
73 
84  template <bool apply_weights, int q>
85  static constexpr auto calculate_G()
86  {
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];
93  }
94  return G;
95  }
96 
97  template <typename T, int q>
98  static auto batch_apply_shape_fn(int jx, tensor<T, q> input, const TensorProductQuadratureRule<q>&)
99  {
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>();
103 
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{})));
106 
107  tensor<tuple<source_t, flux_t>, q> output;
108 
109  for (int qx = 0; qx < q; qx++) {
110  double phi_j = B(qx, jx);
111  double dphi_j_dxi = G(qx, jx);
112 
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)));
117 
118  output[qx] = {d00 * phi_j + d01 * dphi_j_dxi, d10 * phi_j + d11 * dphi_j_dxi};
119  }
120 
121  return output;
122  }
123 
124  template <typename T, int q>
125  static auto batch_apply_shape_fn_interior_face(int jx, tensor<T, q> input, const TensorProductQuadratureRule<q>&)
126  {
127  static constexpr bool apply_weights = false;
128  static constexpr auto B = calculate_B<apply_weights, q>();
129 
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{})));
132 
133  tensor<tuple<source0_t, source1_t>, q> output;
134 
135  for (int qx = 0; qx < q; qx++) {
136  int j = jx % ndof;
137  int s = jx / ndof;
138 
139  double phi0_j = B(qx, j) * (s == 0);
140  double phi1_j = B(qx, j) * (s == 1);
141 
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)));
146 
147  output[qx] = {d00 * phi0_j + d01 * phi1_j, d10 * phi0_j + d11 * phi1_j};
148  }
149 
150  return output;
151  }
152 
153  template <int q>
154  SMITH_HOST_DEVICE static auto interpolate(const dof_type_if& X, const TensorProductQuadratureRule<q>&)
155  {
156  static constexpr bool apply_weights = false;
157  static constexpr auto BT = transpose(calculate_B<apply_weights, q>());
158 
159  tensor<double, q> values{};
160 
161  tensor<tuple<value_type, value_type>, q> output{};
162 
163  // apply the shape functions
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];
169  } else {
170  get<0>(output[qx])[i] = values[qx];
171  }
172  }
173 
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];
178  } else {
179  get<1>(output[qx])[i] = values[qx];
180  }
181  }
182  }
183 
184  return output;
185  }
186 
187  template <int q>
188  SMITH_HOST_DEVICE static auto interpolate(const dof_type& X, const TensorProductQuadratureRule<q>&)
189  {
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>();
193 
194  tensor<double, c, q> value{};
195  tensor<double, c, q> gradient{};
196 
197  // apply the shape functions
198  for (int i = 0; i < c; i++) {
199  value(i) = dot(B, X[i]);
200  gradient(i) = dot(G, X[i]);
201  }
202 
203  // transpose the quadrature data into a tensor of tuples
204  tensor<qf_input_type, q> output;
205 
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);
210  } else {
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);
214  }
215  }
216  }
217 
218  return output;
219  }
220 
221  template <typename source_type, typename flux_type, int q>
222  SMITH_HOST_DEVICE static void integrate(const tensor<tuple<source_type, flux_type>, q>& qf_output,
223  const TensorProductQuadratureRule<q>&, dof_type* element_residual,
224  [[maybe_unused]] int step = 1)
225  {
226  if constexpr (is_zero<source_type>{} && is_zero<flux_type>{}) {
227  return;
228  }
229 
230  constexpr int ntrial = std::max(size(source_type{}), size(flux_type{}) / dim) / c;
231 
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> >;
234 
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>();
238 
239  for (int j = 0; j < ntrial; j++) {
240  for (int i = 0; i < c; i++) {
241  s_buffer_type source;
242  f_buffer_type flux;
243 
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];
247  }
248  if constexpr (!is_zero<flux_type>{}) {
249  flux(qx) = reinterpret_cast<const double*>(&get<FLUX>(qf_output[qx]))[i * ntrial + j];
250  }
251  }
252 
253  element_residual[j * step](i) += dot(source, B) + dot(flux, G);
254  }
255  }
256  }
257 
258  template <typename T, int q>
259  SMITH_HOST_DEVICE static void integrate(const tensor<tuple<T, T>, q>& qf_output,
260  const TensorProductQuadratureRule<q>&, dof_type_if* element_residual,
261  [[maybe_unused]] int step = 1)
262  {
263  constexpr int ntrial = size(T{}) / c;
264 
265  using buffer_type = tensor<double, q>;
266 
267  static constexpr bool apply_weights = true;
268  static constexpr auto B = calculate_B<apply_weights, q>();
269 
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;
274 
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];
278  }
279 
280  element_residual[j * step](i, 0) += dot(source_0, B);
281  element_residual[j * step](i, 1) += dot(source_1, B);
282  }
283  }
284  }
285 };
#define SMITH_HOST_DEVICE
Macro that evaluates to __host__ __device__ when compiling with nvcc or amdclang and does nothing on ...
Definition: accelerator.hpp:37
constexpr SMITH_HOST_DEVICE auto type(const tuple< T... > &values)
a function intended to be used for extracting the ith type from a tuple.
Definition: tuple.hpp:376
SMITH_HOST_DEVICE auto max(dual< gradient_type > a, double b)
Implementation of max for dual numbers.
Definition: dual.hpp:229
constexpr SMITH_HOST_DEVICE int size(const tensor< T, n... > &)
returns the total number of stored values in a tensor
Definition: tensor.hpp:1939
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