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 = 0; // entDim = 0
21  int numEdge = 0; // entDim = 1
22  int numTri = 0; // entDim = 2
23  int numQuad = 0; // entDim = 2
24  int numTet = 0; // entDim = 3
25  int numHex = 0; // entDim = 3
26  int numPrism = 0; // entDim = 3
27  int numPyramid = 0; // entDim = 3
28  int dim = 0;
29 
31  int numEntities(Mesh_Topology topo) const {
32  switch (topo) {
33  case Vertex:
34  return numVtx;
35  case Edge:
36  return numEdge;
37  case Triangle:
38  return numTri;
39  case Quad:
40  return numQuad;
41  case Tetrahedron:
42  return numTet;
43  case Hexahedron:
44  return numHex;
45  case Prism:
46  return numPrism;
47  case Pyramid:
48  return numPyramid;
49  }
50  return 0;
51  }
52 };
53 
64 template <typename Ctrlr, typename Field> struct FieldWithController {
65  Ctrlr ctrlr;
66  Field field;
67 };
68 
98 template <size_t numCompIn, typename Shape, typename... Mixins>
99 struct ShapeField : public Mixins... {
100  Shape shape;
101  static const size_t numComp = numCompIn;
102  const MeshInfo meshInfo;
103  constexpr static auto Order = Shape::Order;
104  // Mixins&&... binds only to rvalues/temporaries (braced-init-list call
105  // sites like ShapeField(meshInfo, {vtxField}) are fine; passing a named
106  // lvalue requires std::move). mixins is moved-from by std::forward below
107  // - do not read mixins again after the initializer list.
108  ShapeField(const MeshInfo &meshInfoIn, Mixins &&... mixins)
109  : meshInfo(meshInfoIn), Mixins( std::forward<Mixins>(mixins) )... {};
110 };
112 
133 template <typename VtxAccessor, typename EdgeAccessor>
135  constexpr static const Mesh_Topology topo[2] = {Vertex, Edge};
136  VtxAccessor vtxField;
137  EdgeAccessor edgeField;
138  using BaseType = typename VtxAccessor::BaseType;
139 
140  KOKKOS_FUNCTION
141  auto &operator()(int entity, int node, int component, Mesh_Topology t) const {
142  if (t != Vertex && t != Edge) {
143  Kokkos::printf("%d is not a support topology\n", t);
144  assert(false);
145  }
146  return (t == Vertex) ? vtxField(entity, node, component)
147  : edgeField(entity, node, component);
148  }
149 };
151 
167 template <typename VtxAccessor> struct LinearAccessor {
168  constexpr static const Mesh_Topology topo[1] = {Vertex};
169  VtxAccessor vtxField;
170  using BaseType = typename VtxAccessor::BaseType;
171 
172  KOKKOS_FUNCTION
173  auto &operator()(int entity, int node, int component, Mesh_Topology t) const {
174  if (t != Vertex) {
175  Kokkos::printf("%d is not a support topology\n", t);
176  assert(false);
177  }
178  return vtxField(entity, node, component);
179  }
180 };
182 
203 template <typename ExecutionSpace,
204  template <typename...>
205  typename Controller = MeshField::KokkosController,
206  typename DataType, size_t order, size_t dim, size_t numComp>
207 auto CreateLagrangeField(const MeshInfo &meshInfo) {
208  static_assert((std::is_same_v<Real4, DataType> == true ||
209  std::is_same_v<Real8, DataType> == true),
210  "CreateLagrangeField only supports single and double precision "
211  "floating point fields\n");
212  static_assert(
213  (order == 1 || order == 2),
214  "CreateLagrangeField only supports linear and quadratic fields\n");
215  static_assert((dim == 1 || dim == 2 || dim == 3),
216  "CreateLagrangeField only supports 1d, 2d, and 3d meshes\n");
217  using MemorySpace = typename ExecutionSpace::memory_space;
218  if constexpr (order == 1 && (dim == 1 || dim == 2 || dim == 3)) {
219  if (meshInfo.numVtx <= 0) {
220  fail("mesh has no vertices\n");
221  }
222 #ifdef MESHFIELDS_ENABLE_CABANA
223  using Ctrlr = std::conditional_t<
224  std::is_same_v<
225  Controller<ExecutionSpace, MemorySpace, DataType>,
226  MeshField::CabanaController<ExecutionSpace, MemorySpace, DataType>>,
227  Controller<ExecutionSpace, MemorySpace, DataType[1][numComp]>,
228  Controller<MemorySpace, ExecutionSpace, DataType ***>>;
229  // 1 dof with 1 component per vtx
230  auto createController = [](auto numVtx) {
231  if constexpr (std::is_same_v<
232  Controller<ExecutionSpace, MemorySpace, DataType>,
233  MeshField::CabanaController<ExecutionSpace, MemorySpace,
234  DataType>>) {
235  return Ctrlr({numVtx});
236  } else {
237  return Ctrlr({/*field 0*/ numVtx, 1, numComp});
238  }
239  };
240  Ctrlr kk_ctrl = createController(meshInfo.numVtx);
241 #else
242  using Ctrlr = Controller<MemorySpace, ExecutionSpace, DataType ***>;
243  Ctrlr kk_ctrl({/*field 0*/ meshInfo.numVtx, 1, numComp});
244 #endif
245  auto vtxField = MeshField::makeField<Ctrlr, 0>(kk_ctrl);
246  using LA = LinearAccessor<decltype(vtxField)>;
247  // clang-format off
248  using LinearLagrangeShapeField = std::conditional_t<
249  dim == 3,
250  ShapeField<numComp, LinearTetrahedronShape, LA>,
251  ShapeField<numComp, LinearTriangleShape, LA>>;
252  // clang-format on
253  LinearLagrangeShapeField llsf(meshInfo, {vtxField});
254  return FieldWithController<Ctrlr, LinearLagrangeShapeField>{kk_ctrl, llsf};
255  } else if constexpr (order == 2 && (dim == 2 || dim == 3)) {
257  if (meshInfo.numVtx <= 0) {
258  fail("mesh has no vertices\n");
259  }
260  if (meshInfo.numEdge <= 0) {
261  fail("mesh has no edges\n");
262  }
263 #ifdef MESHFIELDS_ENABLE_CABANA
264  using Ctrlr = std::conditional_t<
265  std::is_same_v<
266  Controller<ExecutionSpace, MemorySpace, DataType>,
267  MeshField::CabanaController<ExecutionSpace, MemorySpace, DataType>>,
268  Controller<ExecutionSpace, MemorySpace, DataType[1][numComp],
269  DataType[1][numComp]>,
270  Controller<MemorySpace, ExecutionSpace, DataType ***, DataType ***>>;
271  // 1 dof with 1 comp per vtx/edge
272  auto createController = [](auto numVtx, auto numEdge) {
273  if constexpr (std::is_same_v<
274  Controller<ExecutionSpace, MemorySpace, DataType>,
275  MeshField::CabanaController<ExecutionSpace, MemorySpace,
276  DataType>>) {
277  return Ctrlr({numVtx, numEdge});
278  } else {
279  return Ctrlr({/*field 0*/ numVtx, 1, numComp,
280  /*field 1*/ numEdge, 1, numComp});
281  }
282  };
283  Ctrlr kk_ctrl = createController(meshInfo.numVtx, meshInfo.numEdge);
284 #else
285  using Ctrlr =
286  Controller<MemorySpace, ExecutionSpace, DataType ***, DataType ***>;
287  Ctrlr kk_ctrl({/*field 0*/ meshInfo.numVtx, 1, numComp,
288  /*field 1*/ meshInfo.numEdge, 1, numComp});
289 #endif
290  auto vtxField = MeshField::makeField<Ctrlr, 0>(kk_ctrl);
291  auto edgeField = MeshField::makeField<Ctrlr, 1>(kk_ctrl);
292  using QA = QuadraticAccessor<decltype(vtxField), decltype(edgeField)>;
293  // clang-format off
294  using QuadraticLagrangeShapeField = std::conditional_t<
295  dim == 3,
296  ShapeField<numComp, QuadraticTetrahedronShape, QA>,
297  ShapeField<numComp, QuadraticTriangleShape, QA>>;
298  // clang-format on
299  QuadraticLagrangeShapeField qlsf(meshInfo, {vtxField, edgeField});
300  return FieldWithController<Ctrlr, QuadraticLagrangeShapeField>{kk_ctrl,
301  qlsf};
303  } else {
304  fail("CreateLagrangeField does not support the specified "
305  "combination of order %d and dimension %d.\n",
306  order, dim);
307  return FieldWithController<int, std::nullptr_t>{}; // silence compiler warning
308  }
309 };
310 
328 template <typename ExecutionSpace,
329  template <typename...>
330  typename Controller = MeshField::KokkosController,
331  size_t dim>
332 auto CreateCoordinateField(const MeshInfo &meshInfo) {
333  // current coordinate fields are assumed to be linear over the elements
334  return CreateLagrangeField<ExecutionSpace, Controller, Real, 1, dim, dim>(meshInfo);
335 }
336 
337 } // namespace MeshField
338 
339 #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.
int numEntities(Mesh_Topology topo) const
runtime map of number of entities based on topology
Enable definition of field classes with multiple inheritance.