1 #ifndef MESHFIELD_MESHFIELD_HPP
2 #define MESHFIELD_MESHFIELD_HPP
4 #include "KokkosController.hpp"
5 #include "MeshField_Element.hpp"
6 #include "MeshField_Fail.hpp"
7 #include "MeshField_For.hpp"
8 #include "MeshField_ShapeField.hpp"
9 #include "Omega_h_file.hpp"
10 #include "Omega_h_mesh.hpp"
11 #include "Omega_h_simplex.hpp"
17 meshInfo.dim = mesh.dim();
18 meshInfo.numVtx = mesh.nverts();
20 meshInfo.numEdge = mesh.nedges();
21 if (mesh.family() == OMEGA_H_SIMPLEX) {
23 meshInfo.numTri = mesh.nfaces();
25 meshInfo.numTet = mesh.nregions();
28 meshInfo.numQuad = mesh.nfaces();
30 meshInfo.numHex = mesh.nregions();
35 template <
typename ExecutionSpace,
size_t dim,
36 template <
typename...>
37 typename Controller = MeshField::KokkosController>
38 decltype(MeshField::CreateCoordinateField<ExecutionSpace, Controller, dim>(
40 createCoordinateField(const MeshField::MeshInfo &mesh_info,
41 Omega_h::Reals coords) {
42 const auto meshDim = mesh_info.dim;
43 auto coordFieldWithCtrlr =
44 MeshField::CreateCoordinateField<ExecutionSpace, Controller, dim>(
46 auto coordField = coordFieldWithCtrlr.field;
47 auto setCoordField = KOKKOS_LAMBDA(
const int &i) {
48 coordField(i, 0, 0, MeshField::Vertex) = coords[i * meshDim];
49 coordField(i, 0, 1, MeshField::Vertex) = coords[i * meshDim + 1];
50 if constexpr (dim == 3) {
51 coordField(i, 0, 2, MeshField::Vertex) = coords[i * meshDim + 2];
54 MeshField::parallel_for(ExecutionSpace(), {0}, {mesh_info.numVtx},
55 setCoordField,
"setCoordField");
56 return coordFieldWithCtrlr;
64 struct LinearTriangleToVertexField {
65 Omega_h::LOs triVerts;
66 LinearTriangleToVertexField(Omega_h::Mesh &mesh)
67 : triVerts(mesh.ask_elem_verts()) {
68 if (mesh.dim() != 2 && mesh.family() != OMEGA_H_SIMPLEX) {
70 "The mesh passed to %s must be 2D and simplex (triangles)\n",
75 static constexpr KOKKOS_FUNCTION Kokkos::Array<MeshField::Mesh_Topology, 1>
77 return {MeshField::Triangle};
81 operator()(MeshField::LO triNodeIdx, MeshField::LO triCompIdx,
82 MeshField::LO tri, MeshField::Mesh_Topology topo)
const {
83 assert(topo == MeshField::Triangle);
84 const auto triDim = 2;
85 const auto vtxDim = 0;
86 const auto ignored = -1;
87 const auto localVtxIdx =
88 (Omega_h::simplex_down_template(triDim, vtxDim, triNodeIdx, ignored) +
91 const auto triToVtxDegree = Omega_h::simplex_degree(triDim, vtxDim);
92 const MeshField::LO vtx = triVerts[(tri * triToVtxDegree) + localVtxIdx];
93 return {0, triCompIdx, vtx, MeshField::Vertex};
96 struct LinearTetrahedronToVertexField {
97 Omega_h::LOs tetVerts;
98 LinearTetrahedronToVertexField(Omega_h::Mesh &mesh)
99 : tetVerts(mesh.ask_elem_verts()) {
100 if (mesh.dim() != 3 && mesh.family() != OMEGA_H_SIMPLEX) {
102 "The mesh passed to %s must be 3D and simplex (tetrahedron)\n",
106 static constexpr KOKKOS_FUNCTION Kokkos::Array<MeshField::Mesh_Topology, 1>
108 return {MeshField::Tetrahedron};
112 operator()(MeshField::LO tetNodeIdx, MeshField::LO tetCompIdx,
113 MeshField::LO tet, MeshField::Mesh_Topology topo)
const {
114 assert(topo == MeshField::Tetrahedron);
115 const auto tetDim = 3;
116 const auto vtxDim = 0;
117 const auto ignored = -1;
118 const auto localVtxIdx =
119 (Omega_h::simplex_down_template(tetDim, vtxDim, tetNodeIdx, ignored) +
122 const auto tetToVtxDegree = Omega_h::simplex_degree(tetDim, vtxDim);
123 const MeshField::LO vtx = tetVerts[(tet * tetToVtxDegree) + localVtxIdx];
124 return {0, tetCompIdx, vtx, MeshField::Vertex};
129 Omega_h::LOs triVerts;
130 Omega_h::LOs triEdges;
132 : triVerts(mesh.ask_elem_verts()),
133 triEdges(mesh.ask_down(mesh.dim(), 1).ab2b) {
134 if (mesh.dim() != 2 && mesh.family() != OMEGA_H_SIMPLEX) {
136 "The mesh passed to %s must be 2D and simplex (triangles)\n",
141 static constexpr KOKKOS_FUNCTION Kokkos::Array<MeshField::Mesh_Topology, 1>
143 return {MeshField::Triangle};
147 operator()(MeshField::LO triNodeIdx, MeshField::LO triCompIdx,
148 MeshField::LO tri, MeshField::Mesh_Topology topo)
const {
149 assert(topo == MeshField::Triangle);
152 const MeshField::LO triNode2DofHolder[6] = {
155 const MeshField::Mesh_Topology triNode2DofHolderTopo[6] = {
157 MeshField::Vertex, MeshField::Vertex, MeshField::Vertex,
159 MeshField::Edge, MeshField::Edge, MeshField::Edge};
160 const auto dofHolderIdx = triNode2DofHolder[triNodeIdx];
161 const auto dofHolderTopo = triNode2DofHolderTopo[triNodeIdx];
165 if (dofHolderTopo == MeshField::Vertex) {
166 const auto triDim = 2;
167 const auto vtxDim = 0;
168 const auto ignored = -1;
169 const auto localVtxIdx = (Omega_h::simplex_down_template(
170 triDim, vtxDim, dofHolderIdx, ignored) +
173 const auto triToVtxDegree = Omega_h::simplex_degree(triDim, vtxDim);
174 osh_ent = triVerts[(tri * triToVtxDegree) + localVtxIdx];
175 }
else if (dofHolderTopo == MeshField::Edge) {
176 const auto triDim = 2;
177 const auto edgeDim = 1;
178 const auto triToEdgeDegree = Omega_h::simplex_degree(triDim, edgeDim);
182 osh_ent = triEdges[(tri * triToEdgeDegree) + (dofHolderIdx + 2) % 3];
186 return {0, triCompIdx, osh_ent, dofHolderTopo};
192 Omega_h::LOs tetVerts;
193 Omega_h::LOs tetEdges;
195 : tetVerts(mesh.ask_elem_verts()),
196 tetEdges(mesh.ask_down(mesh.dim(), 1).ab2b) {
197 if (mesh.dim() != 3 && mesh.family() != OMEGA_H_SIMPLEX) {
199 "The mesh passed to %s must be 3D and simplex (tetrahedron)",
204 static constexpr KOKKOS_FUNCTION Kokkos::Array<MeshField::Mesh_Topology, 1>
206 return {MeshField::Tetrahedron};
210 operator()(MeshField::LO tetNodeIdx, MeshField::LO tetCompIdx,
211 MeshField::LO tet, MeshField::Mesh_Topology topo)
const {
212 assert(topo == MeshField::Tetrahedron);
213 const MeshField::LO tetNode2DofHolder[10] = {0, 1, 2, 3, 3, 4, 5, 0, 1, 2};
214 const MeshField::Mesh_Topology tetNode2DofHolderTopo[10] = {
215 MeshField::Vertex, MeshField::Vertex, MeshField::Vertex,
216 MeshField::Vertex, MeshField::Edge, MeshField::Edge,
217 MeshField::Edge, MeshField::Edge, MeshField::Edge,
219 const auto dofHolderIdx = tetNode2DofHolder[tetNodeIdx];
220 const auto dofHolderTopo = tetNode2DofHolderTopo[tetNodeIdx];
222 if (dofHolderTopo == MeshField::Vertex) {
223 const auto tetDim = 3;
224 const auto vtxDim = 0;
225 const auto ignored = -1;
228 const auto localVtxIdx = (Omega_h::simplex_down_template(
229 tetDim, vtxDim, dofHolderIdx, ignored) +
232 const auto tetToVtxDegree = Omega_h::simplex_degree(tetDim, vtxDim);
233 osh_ent = tetVerts[(tet * tetToVtxDegree) + localVtxIdx];
234 }
else if (dofHolderTopo == MeshField::Edge) {
235 const auto tetDim = 3;
236 const auto edgeDim = 1;
237 const auto tetToEdgeDegree = Omega_h::simplex_degree(tetDim, edgeDim);
238 osh_ent = tetEdges[(tet * tetToEdgeDegree) + dofHolderIdx];
242 return {0, tetCompIdx, osh_ent, dofHolderTopo};
247 template <
int ShapeOrder>
auto getTriangleElement(Omega_h::Mesh &mesh) {
248 static_assert(ShapeOrder == 1 || ShapeOrder == 2);
249 if constexpr (ShapeOrder == 1) {
252 LinearTriangleToVertexField map;
255 LinearTriangleToVertexField(mesh)};
256 }
else if constexpr (ShapeOrder == 2) {
259 QuadraticTriangleToField map;
262 QuadraticTriangleToField(mesh)};
266 template <
int ShapeOrder>
auto getTetrahedronElement(Omega_h::Mesh &mesh) {
267 static_assert(ShapeOrder == 1 || ShapeOrder == 2);
268 if constexpr (ShapeOrder == 1) {
271 LinearTetrahedronToVertexField map;
274 LinearTetrahedronToVertexField(mesh)};
275 }
else if constexpr (ShapeOrder == 2) {
278 QuadraticTetrahedronToField map;
281 QuadraticTetrahedronToField(mesh)};
287 template <
typename ExecutionSpace,
size_t dim,
288 template <
typename...>
typename Controller =
289 MeshField::KokkosController>
290 class OmegahMeshField {
295 decltype(createCoordinateField<ExecutionSpace, dim, Controller>(
297 CoordField coordField;
300 OmegahMeshField(Omega_h::Mesh &mesh_in)
301 : mesh(mesh_in), meshInfo(getMeshInfo(mesh)),
302 coordField(createCoordinateField<ExecutionSpace, dim, Controller>(
303 getMeshInfo(mesh_in), mesh_in.coords())) {
304 static_assert(dim == 1 || dim == 2 || dim == 3);
307 template <
typename DataType,
size_t order,
size_t numComp>
309 auto CreateLagrangeField()
const {
310 return MeshField::CreateLagrangeField<ExecutionSpace, Controller, DataType,
311 order, dim, numComp>(meshInfo);
314 auto getCoordField() {
return coordField; }
317 template <
typename Field>
void writeVtk(Field &field)
const {
318 using FieldDataType =
typename decltype(field.vtxField)::BaseType;
320 auto field_view = field.vtxField.serialize();
321 Omega_h::Write<FieldDataType> field_write(field_view);
322 mesh.add_tag(0,
"field", 1, Omega_h::read(field_write),
false,
323 Omega_h::ArrayType::VectorND);
324 Omega_h::vtk::write_parallel(
"foo.vtk", &mesh, mesh.dim());
327 template <
typename ViewType = Kokkos::View<MeshField::LO *>>
328 ViewType createOffsets(
size_t numTri,
size_t numPtsPerElem)
const {
329 ViewType offsets(
"offsets", numTri + 1);
330 Kokkos::parallel_for(
331 "setOffsets", numTri,
332 KOKKOS_LAMBDA(
int i) { offsets(i) = i * numPtsPerElem; });
333 Kokkos::deep_copy(Kokkos::subview(offsets, offsets.size() - 1),
334 numTri * numPtsPerElem);
339 template <
typename ViewType,
typename ShapeField>
340 auto triangleLocalPointEval(
const ViewType &localCoords,
size_t NumPtsPerElem,
341 const ShapeField &field)
const {
342 auto offsets = createOffsets(meshInfo.numTri, NumPtsPerElem);
343 auto eval = triangleLocalPointEval<ViewType, ShapeField>(localCoords,
349 template <
typename ViewType,
typename ShapeField>
350 auto triangleLocalPointEval(
const ViewType &localCoords,
351 Kokkos::View<LO *> offsets,
352 const ShapeField &field)
const {
353 const auto MeshDim = 2;
354 if (mesh.dim() != MeshDim) {
355 MeshField::fail(
"input mesh must be 2d\n");
357 const auto ShapeOrder = ShapeField::Order;
358 if (ShapeOrder != 1 && ShapeOrder != 2) {
359 MeshField::fail(
"input field order must be 1 or 2\n");
362 const auto [shp, map] = Omegah::getTriangleElement<ShapeOrder>(mesh);
365 meshInfo.numTri, field, shp, map);
366 auto eval = MeshField::evaluate(f, localCoords, offsets);
370 template <
typename ViewType,
typename ShapeField>
371 auto tetrahedronLocalPointEval(
const ViewType &localCoords,
372 size_t NumPtsPerElem,
373 const ShapeField &field)
const {
374 auto offsets = createOffsets(meshInfo.numTet, NumPtsPerElem);
375 auto eval = tetrahedronLocalPointEval(localCoords, offsets, field);
379 template <
typename ViewType,
typename ShapeField>
380 auto tetrahedronLocalPointEval(
const ViewType &localCoords,
381 Kokkos::View<LO *> offsets,
382 const ShapeField &field)
const {
383 const auto MeshDim = 3;
384 if (mesh.dim() != MeshDim) {
385 MeshField::fail(
"input mesh must be 3d\n");
387 const auto ShapeOrder = ShapeField::Order;
388 if (ShapeOrder != 1 && ShapeOrder != 2) {
389 MeshField::fail(
"input field order must be 1 or 2\n");
391 const auto [shp, map] = Omegah::getTetrahedronElement<ShapeOrder>(mesh);
393 meshInfo.numTet, field, shp, map);
394 auto eval = MeshField::evaluate(f, localCoords, offsets);
Supports mapping between mesh (i.e., Omega_h) ordering and MeshFields ordering.
Supports the evaluation of a field, and other per-element operations, given the definition of the ele...
Linear (P1) shape functions for 2D triangular elements.
On-process mesh metadata.
[QuadraticTriangleToField]
[QuadraticTriangleToField]
Quadratic (P2) shape functions for 3D tetrahedral elements.
Quadratic (P2) shape functions for 2D triangular elements.