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 Controller, 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  using Ctrlr=Controller;
105  // Mixins&&... binds only to rvalues/temporaries (braced-init-list call
106  // sites like ShapeField(meshInfo, {vtxField}) are fine; passing a named
107  // lvalue requires std::move). mixins is moved-from by std::forward below
108  // - do not read mixins again after the initializer list.
109  ShapeField(const MeshInfo &meshInfoIn, Mixins &&... mixins)
110  : meshInfo(meshInfoIn), Mixins( std::forward<Mixins>(mixins) )... {};
111 };
113 
134 template <typename VtxAccessor, typename EdgeAccessor>
136  constexpr static const Mesh_Topology topo[2] = {Vertex, Edge};
137  VtxAccessor vtxField;
138  EdgeAccessor edgeField;
139  using BaseType = typename VtxAccessor::BaseType;
140 
141  KOKKOS_FUNCTION
142  auto &operator()(int entity, int node, int component, Mesh_Topology t) const {
143  if (t != Vertex && t != Edge) {
144  Kokkos::printf("%d is not a support topology\n", t);
145  assert(false);
146  }
147  return (t == Vertex) ? vtxField(entity, node, component)
148  : edgeField(entity, node, component);
149  }
150 };
152 
168 template <typename VtxAccessor> struct LinearAccessor {
169  constexpr static const Mesh_Topology topo[1] = {Vertex};
170  VtxAccessor vtxField;
171  using BaseType = typename VtxAccessor::BaseType;
172 
173  KOKKOS_FUNCTION
174  auto &operator()(int entity, int node, int component, Mesh_Topology t) const {
175  if (t != Vertex) {
176  Kokkos::printf("%d is not a support topology\n", t);
177  assert(false);
178  }
179  return vtxField(entity, node, component);
180  }
181 };
183 
204 template <typename ExecutionSpace,
205  template <typename...>
206  typename Controller = MeshField::KokkosController,
207  typename DataType, size_t order, size_t dim, size_t numComp>
208 auto CreateLagrangeField(const MeshInfo &meshInfo) {
209  static_assert((std::is_same_v<Real4, DataType> == true ||
210  std::is_same_v<Real8, DataType> == true),
211  "CreateLagrangeField only supports single and double precision "
212  "floating point fields\n");
213  static_assert(
214  (order == 1 || order == 2),
215  "CreateLagrangeField only supports linear and quadratic fields\n");
216  static_assert((dim == 1 || dim == 2 || dim == 3),
217  "CreateLagrangeField only supports 1d, 2d, and 3d meshes\n");
218  using MemorySpace = typename ExecutionSpace::memory_space;
219  if constexpr (order == 1 && (dim == 1 || dim == 2 || dim == 3)) {
220  if (meshInfo.numVtx <= 0) {
221  fail("mesh has no vertices\n");
222  }
223 #ifdef MESHFIELDS_ENABLE_CABANA
224  using Ctrlr = std::conditional_t<
225  std::is_same_v<
226  Controller<ExecutionSpace, MemorySpace, DataType>,
227  MeshField::CabanaController<ExecutionSpace, MemorySpace, DataType>>,
228  Controller<ExecutionSpace, MemorySpace, DataType[1][numComp]>,
229  Controller<MemorySpace, ExecutionSpace, DataType ***>>;
230  // 1 dof with 1 component per vtx
231  auto createController = [](auto numVtx) {
232  if constexpr (std::is_same_v<
233  Controller<ExecutionSpace, MemorySpace, DataType>,
234  MeshField::CabanaController<ExecutionSpace, MemorySpace,
235  DataType>>) {
236  return Ctrlr({numVtx});
237  } else {
238  return Ctrlr({/*field 0*/ numVtx, 1, numComp});
239  }
240  };
241  Ctrlr kk_ctrl = createController(meshInfo.numVtx);
242 #else
243  using Ctrlr = Controller<MemorySpace, ExecutionSpace, DataType ***>;
244  Ctrlr kk_ctrl({/*field 0*/ meshInfo.numVtx, 1, numComp});
245 #endif
246  auto vtxField = MeshField::makeField<Ctrlr, 0>(kk_ctrl);
247  using LA = LinearAccessor<decltype(vtxField)>;
248  // clang-format off
249  using LinearLagrangeShapeField = std::conditional_t<
250  dim == 3,
251  ShapeField<numComp, LinearTetrahedronShape, Ctrlr, LA>,
252  ShapeField<numComp, LinearTriangleShape, Ctrlr, LA>>;
253  // clang-format on
254  LinearLagrangeShapeField llsf(meshInfo, {vtxField});
255  return FieldWithController<Ctrlr, LinearLagrangeShapeField>{kk_ctrl, llsf};
256  } else if constexpr (order == 2 && (dim == 2 || dim == 3)) {
258  if (meshInfo.numVtx <= 0) {
259  fail("mesh has no vertices\n");
260  }
261  if (meshInfo.numEdge <= 0) {
262  fail("mesh has no edges\n");
263  }
264 #ifdef MESHFIELDS_ENABLE_CABANA
265  using Ctrlr = std::conditional_t<
266  std::is_same_v<
267  Controller<ExecutionSpace, MemorySpace, DataType>,
268  MeshField::CabanaController<ExecutionSpace, MemorySpace, DataType>>,
269  Controller<ExecutionSpace, MemorySpace, DataType[1][numComp],
270  DataType[1][numComp]>,
271  Controller<MemorySpace, ExecutionSpace, DataType ***, DataType ***>>;
272  // 1 dof with 1 comp per vtx/edge
273  auto createController = [](auto numVtx, auto numEdge) {
274  if constexpr (std::is_same_v<
275  Controller<ExecutionSpace, MemorySpace, DataType>,
276  MeshField::CabanaController<ExecutionSpace, MemorySpace,
277  DataType>>) {
278  return Ctrlr({numVtx, numEdge});
279  } else {
280  return Ctrlr({/*field 0*/ numVtx, 1, numComp,
281  /*field 1*/ numEdge, 1, numComp});
282  }
283  };
284  Ctrlr kk_ctrl = createController(meshInfo.numVtx, meshInfo.numEdge);
285 #else
286  using Ctrlr =
287  Controller<MemorySpace, ExecutionSpace, DataType ***, DataType ***>;
288  Ctrlr kk_ctrl({/*field 0*/ meshInfo.numVtx, 1, numComp,
289  /*field 1*/ meshInfo.numEdge, 1, numComp});
290 #endif
291  auto vtxField = MeshField::makeField<Ctrlr, 0>(kk_ctrl);
292  auto edgeField = MeshField::makeField<Ctrlr, 1>(kk_ctrl);
293  using QA = QuadraticAccessor<decltype(vtxField), decltype(edgeField)>;
294  // clang-format off
295  using QuadraticLagrangeShapeField = std::conditional_t<
296  dim == 3,
297  ShapeField<numComp, QuadraticTetrahedronShape, Ctrlr, QA>,
298  ShapeField<numComp, QuadraticTriangleShape, Ctrlr, QA>>;
299  // clang-format on
300  QuadraticLagrangeShapeField qlsf(meshInfo, {vtxField, edgeField});
301  return FieldWithController<Ctrlr, QuadraticLagrangeShapeField>{kk_ctrl,
302  qlsf};
304  } else {
305  fail("CreateLagrangeField does not support the specified "
306  "combination of order %d and dimension %d.\n",
307  order, dim);
308  return FieldWithController<int, std::nullptr_t>{}; // silence compiler warning
309  }
310 };
311 
329 template <typename ExecutionSpace,
330  template <typename...>
331  typename Controller = MeshField::KokkosController,
332  size_t dim>
333 auto CreateCoordinateField(const MeshInfo &meshInfo) {
334  // current coordinate fields are assumed to be linear over the elements
335  return CreateLagrangeField<ExecutionSpace, Controller, Real, 1, dim, dim>(meshInfo);
336 }
337 
338 } // namespace MeshField
339 
340 #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.