MeshFields
GPU accelerated mesh-based fields
MeshField_ShapeField.hpp
1 #ifndef MESHFIELD_SHAPEFIELD_HPP
2 #define MESHFIELD_SHAPEFIELD_HPP
3 
4 #ifdef MESHFIELDS_ENABLE_CABANA
5 #include "CabanaController.hpp"
6 #endif
7 #include "KokkosController.hpp"
8 #include "MeshField_Field.hpp"
9 #include "MeshField_Shape.hpp"
10 #include <type_traits> //decltype
11 #include <utility> // std::forward
12 
13 namespace MeshField {
14 
19 struct MeshInfo {
20  int numVtx; // entDim = 0
21  int numEdge; // entDim = 1
22  int numTri; // entDim = 2
23  int numQuad; // entDim = 2
24  int numTet; // entDim = 3
25  int numHex; // entDim = 3
26  int numPrism; // entDim = 3
27  int numPyramid; // entDim = 3
28  int dim;
29 };
30 
41 template <typename Ctrlr, typename Field> struct FieldWithController {
42  Ctrlr ctrlr;
43  Field field;
44 };
45 
75 template <size_t numCompIn, typename Shape, typename... Mixins>
76 struct ShapeField : public Mixins... {
77  Shape shape;
78  static const size_t numComp = numCompIn;
79  const MeshInfo meshInfo;
80  constexpr static auto Order = Shape::Order;
81  // Mixins&&... binds only to rvalues/temporaries (braced-init-list call
82  // sites like ShapeField(meshInfo, {vtxField}) are fine; passing a named
83  // lvalue requires std::move). mixins is moved-from by std::forward below
84  // - do not read mixins again after the initializer list.
85  ShapeField(const MeshInfo &meshInfoIn, Mixins &&... mixins)
86  : meshInfo(meshInfoIn), Mixins( std::forward<Mixins>(mixins) )... {};
87 };
89 
110 template <typename VtxAccessor, typename EdgeAccessor>
112  constexpr static const Mesh_Topology topo[2] = {Vertex, Edge};
113  VtxAccessor vtxField;
114  EdgeAccessor edgeField;
115  using BaseType = typename VtxAccessor::BaseType;
116 
117  KOKKOS_FUNCTION
118  auto &operator()(int entity, int node, int component, Mesh_Topology t) const {
119  if (t != Vertex && t != Edge) {
120  Kokkos::printf("%d is not a support topology\n", t);
121  assert(false);
122  }
123  return (t == Vertex) ? vtxField(entity, node, component)
124  : edgeField(entity, node, component);
125  }
126 };
128 
144 template <typename VtxAccessor> struct LinearAccessor {
145  constexpr static const Mesh_Topology topo[1] = {Vertex};
146  VtxAccessor vtxField;
147  using BaseType = typename VtxAccessor::BaseType;
148 
149  KOKKOS_FUNCTION
150  auto &operator()(int entity, int node, int component, Mesh_Topology t) const {
151  if (t != Vertex) {
152  Kokkos::printf("%d is not a support topology\n", t);
153  assert(false);
154  }
155  return vtxField(entity, node, component);
156  }
157 };
159 
180 template <typename ExecutionSpace,
181  template <typename...>
182  typename Controller = MeshField::KokkosController,
183  typename DataType, size_t order, size_t dim, size_t numComp>
184 auto CreateLagrangeField(const MeshInfo &meshInfo) {
185  static_assert((std::is_same_v<Real4, DataType> == true ||
186  std::is_same_v<Real8, DataType> == true),
187  "CreateLagrangeField only supports single and double precision "
188  "floating point fields\n");
189  static_assert(
190  (order == 1 || order == 2),
191  "CreateLagrangeField only supports linear and quadratic fields\n");
192  static_assert((dim == 1 || dim == 2 || dim == 3),
193  "CreateLagrangeField only supports 1d, 2d, and 3d meshes\n");
194  using MemorySpace = typename ExecutionSpace::memory_space;
195  if constexpr (order == 1 && (dim == 1 || dim == 2 || dim == 3)) {
196  if (meshInfo.numVtx <= 0) {
197  fail("mesh has no vertices\n");
198  }
199 #ifdef MESHFIELDS_ENABLE_CABANA
200  using Ctrlr = std::conditional_t<
201  std::is_same_v<
202  Controller<ExecutionSpace, MemorySpace, DataType>,
203  MeshField::CabanaController<ExecutionSpace, MemorySpace, DataType>>,
204  Controller<ExecutionSpace, MemorySpace, DataType[1][numComp]>,
205  Controller<MemorySpace, ExecutionSpace, DataType ***>>;
206  // 1 dof with 1 component per vtx
207  auto createController = [](auto numVtx) {
208  if constexpr (std::is_same_v<
209  Controller<ExecutionSpace, MemorySpace, DataType>,
210  MeshField::CabanaController<ExecutionSpace, MemorySpace,
211  DataType>>) {
212  return Ctrlr({numVtx});
213  } else {
214  return Ctrlr({/*field 0*/ numVtx, 1, numComp});
215  }
216  };
217  Ctrlr kk_ctrl = createController(meshInfo.numVtx);
218 #else
219  using Ctrlr = Controller<MemorySpace, ExecutionSpace, DataType ***>;
220  Ctrlr kk_ctrl({/*field 0*/ meshInfo.numVtx, 1, numComp});
221 #endif
222  auto vtxField = MeshField::makeField<Ctrlr, 0>(kk_ctrl);
223  using LA = LinearAccessor<decltype(vtxField)>;
224  // clang-format off
225  using LinearLagrangeShapeField = std::conditional_t<
226  dim == 3,
227  ShapeField<numComp, LinearTetrahedronShape, LA>,
228  ShapeField<numComp, LinearTriangleShape, LA>>;
229  // clang-format on
230  LinearLagrangeShapeField llsf(meshInfo, {vtxField});
231  return FieldWithController<Ctrlr, LinearLagrangeShapeField>{kk_ctrl, llsf};
232  } else if constexpr (order == 2 && (dim == 2 || dim == 3)) {
234  if (meshInfo.numVtx <= 0) {
235  fail("mesh has no vertices\n");
236  }
237  if (meshInfo.numEdge <= 0) {
238  fail("mesh has no edges\n");
239  }
240 #ifdef MESHFIELDS_ENABLE_CABANA
241  using Ctrlr = std::conditional_t<
242  std::is_same_v<
243  Controller<ExecutionSpace, MemorySpace, DataType>,
244  MeshField::CabanaController<ExecutionSpace, MemorySpace, DataType>>,
245  Controller<ExecutionSpace, MemorySpace, DataType[1][numComp],
246  DataType[1][numComp]>,
247  Controller<MemorySpace, ExecutionSpace, DataType ***, DataType ***>>;
248  // 1 dof with 1 comp per vtx/edge
249  auto createController = [](auto numVtx, auto numEdge) {
250  if constexpr (std::is_same_v<
251  Controller<ExecutionSpace, MemorySpace, DataType>,
252  MeshField::CabanaController<ExecutionSpace, MemorySpace,
253  DataType>>) {
254  return Ctrlr({numVtx, numEdge});
255  } else {
256  return Ctrlr({/*field 0*/ numVtx, 1, numComp,
257  /*field 1*/ numEdge, 1, numComp});
258  }
259  };
260  Ctrlr kk_ctrl = createController(meshInfo.numVtx, meshInfo.numEdge);
261 #else
262  using Ctrlr =
263  Controller<MemorySpace, ExecutionSpace, DataType ***, DataType ***>;
264  Ctrlr kk_ctrl({/*field 0*/ meshInfo.numVtx, 1, numComp,
265  /*field 1*/ meshInfo.numEdge, 1, numComp});
266 #endif
267  auto vtxField = MeshField::makeField<Ctrlr, 0>(kk_ctrl);
268  auto edgeField = MeshField::makeField<Ctrlr, 1>(kk_ctrl);
269  using QA = QuadraticAccessor<decltype(vtxField), decltype(edgeField)>;
270  // clang-format off
271  using QuadraticLagrangeShapeField = std::conditional_t<
272  dim == 3,
273  ShapeField<numComp, QuadraticTetrahedronShape, QA>,
274  ShapeField<numComp, QuadraticTriangleShape, QA>>;
275  // clang-format on
276  QuadraticLagrangeShapeField qlsf(meshInfo, {vtxField, edgeField});
277  return FieldWithController<Ctrlr, QuadraticLagrangeShapeField>{kk_ctrl,
278  qlsf};
280  } else {
281  fail("CreateLagrangeField does not support the specified "
282  "combination of order %d and dimension %d.\n",
283  order, dim);
284  return FieldWithController<int, std::nullptr_t>{}; // silence compiler warning
285  }
286 };
287 
305 template <typename ExecutionSpace,
306  template <typename...>
307  typename Controller = MeshField::KokkosController,
308  size_t dim>
309 auto CreateCoordinateField(const MeshInfo &meshInfo) {
310  if (meshInfo.numVtx <= 0) {
311  fail("mesh has no vertices\n");
312  }
313  using DataType = Real;
314  using MemorySpace = typename ExecutionSpace::memory_space;
315  const int numComp = meshInfo.dim;
316 #ifdef MESHFIELDS_ENABLE_CABANA
317  using Ctrlr = std::conditional_t<
318  std::is_same_v<
319  Controller<ExecutionSpace, MemorySpace, DataType>,
320  MeshField::CabanaController<ExecutionSpace, MemorySpace, DataType>>,
321  Controller<ExecutionSpace, MemorySpace, DataType[1][dim]>,
322  Controller<MemorySpace, ExecutionSpace, DataType ***>>;
323  auto createController = [](const int numComp, auto numVtx) {
324  if constexpr (std::is_same_v<
325  Controller<ExecutionSpace, MemorySpace, DataType>,
326  MeshField::CabanaController<ExecutionSpace, MemorySpace,
327  DataType>>) {
328  return Ctrlr({numVtx});
329  } else {
330  return Ctrlr({/*field 0*/ numVtx, 1, numComp});
331  }
332  };
333  Ctrlr kk_ctrl = createController(numComp, meshInfo.numVtx);
334 #else
335  using Ctrlr = Controller<MemorySpace, ExecutionSpace, DataType ***>;
336  Ctrlr kk_ctrl({/*field 0*/ meshInfo.numVtx, 1, numComp});
337 #endif
338  auto vtxField = MeshField::makeField<Ctrlr, 0>(kk_ctrl);
339  using LA = LinearAccessor<decltype(vtxField)>;
340  using LinearLagrangeShapeField =
341  ShapeField<dim, LinearTriangleShape, LA>;
342  LinearLagrangeShapeField llsf(meshInfo, {vtxField});
343  return FieldWithController<Ctrlr, LinearLagrangeShapeField>{kk_ctrl, llsf};
344 };
345 
346 } // namespace MeshField
347 
348 #endif
Shape function definitions for finite element analysis.
Provides access to individual entries of a single Field provided by MeshField::makeField and helper f...
Return type of CreateLagrangeField/CreateCoordinateField.
On-process mesh metadata.
Enable definition of field classes with multiple inheritance.