@@ -89,6 +89,37 @@ struct LinearTriangleToVertexField {
8989 return {0 , triCompIdx, vtx, MeshField::Vertex}; // node, comp, ent, topo
9090 }
9191};
92+ struct LinearTetrahedronToVertexField {
93+ Omega_h::LOs tetVerts;
94+ LinearTetrahedronToVertexField (Omega_h::Mesh &mesh)
95+ : tetVerts(mesh.ask_elem_verts()) {
96+ if (mesh.dim () != 3 && mesh.family () != OMEGA_H_SIMPLEX) {
97+ MeshField::fail (
98+ " The mesh passed to %s must be 3D and simplex (tetrahedron)\n " ,
99+ __func__);
100+ }
101+ }
102+ KOKKOS_FUNCTION Kokkos::Array<MeshField::Mesh_Topology, 1 >
103+ getTopology () const {
104+ return {MeshField::Tetrahedron};
105+ }
106+
107+ KOKKOS_FUNCTION MeshField::ElementToDofHolderMap
108+ operator ()(MeshField::LO tetNodeIdx, MeshField::LO tetCompIdx,
109+ MeshField::LO tet, MeshField::Mesh_Topology topo) const {
110+ assert (topo == MeshField::Tetrahedron);
111+ const auto tetDim = 3 ;
112+ const auto vtxDim = 0 ;
113+ const auto ignored = -1 ;
114+ const auto localVtxIdx =
115+ (Omega_h::simplex_down_template (tetDim, vtxDim, tetNodeIdx, ignored) +
116+ 3 ) %
117+ 4 ;
118+ const auto tetToVtxDegree = Omega_h::simplex_degree (tetDim, vtxDim);
119+ const MeshField::LO vtx = tetVerts[(tet * tetToVtxDegree) + localVtxIdx];
120+ return {0 , tetCompIdx, vtx, MeshField::Vertex}; // node, comp, ent, topo
121+ }
122+ };
92123struct QuadraticTriangleToField {
93124 Omega_h::LOs triVerts;
94125 Omega_h::LOs triEdges;
@@ -151,6 +182,59 @@ struct QuadraticTriangleToField {
151182 }
152183};
153184
185+ struct QuadraticTetrahedronToField {
186+ Omega_h::LOs tetVerts;
187+ Omega_h::LOs tetEdges;
188+ QuadraticTetrahedronToField (Omega_h::Mesh &mesh)
189+ : tetVerts(mesh.ask_elem_verts()),
190+ tetEdges (mesh.ask_down(mesh.dim(), 1).ab2b) {
191+ if (mesh.dim () != 3 && mesh.family () != OMEGA_H_SIMPLEX) {
192+ MeshField::fail (
193+ " The mesh passed to %s must be 3D and simplex (tetrahedron)" ,
194+ __func__);
195+ }
196+ }
197+
198+ KOKKOS_FUNCTION Kokkos::Array<MeshField::Mesh_Topology, 1 >
199+ getTopology () const {
200+ return {MeshField::Tetrahedron};
201+ }
202+
203+ KOKKOS_FUNCTION MeshField::ElementToDofHolderMap
204+ operator ()(MeshField::LO tetNodeIdx, MeshField::LO tetCompIdx,
205+ MeshField::LO tet, MeshField::Mesh_Topology topo) const {
206+ assert (topo == MeshField::Tetrahedron);
207+ const MeshField::LO tetNode2DofHolder[10 ] = {0 , 1 , 2 , 3 , 3 , 4 , 5 , 0 , 2 , 1 };
208+ const MeshField::Mesh_Topology tetNode2DofHolderTopo[10 ] = {
209+ MeshField::Vertex, MeshField::Vertex, MeshField::Vertex,
210+ MeshField::Vertex, MeshField::Edge, MeshField::Edge,
211+ MeshField::Edge, MeshField::Edge, MeshField::Edge,
212+ MeshField::Edge};
213+ const auto dofHolderIdx = tetNode2DofHolder[tetNodeIdx];
214+ const auto dofHolderTopo = tetNode2DofHolderTopo[tetNodeIdx];
215+ Omega_h::LO osh_ent;
216+ if (dofHolderTopo == MeshField::Vertex) {
217+ const auto tetDim = 3 ;
218+ const auto vtxDim = 0 ;
219+ const auto ignored = -1 ;
220+ const auto localVtxIdx = (Omega_h::simplex_down_template (
221+ tetDim, vtxDim, dofHolderIdx, ignored) +
222+ 3 ) %
223+ 4 ;
224+ const auto tetToVtxDegree = Omega_h::simplex_degree (tetDim, vtxDim);
225+ osh_ent = tetVerts[(tet * tetToVtxDegree) + localVtxIdx];
226+ } else if (dofHolderTopo == MeshField::Edge) {
227+ const auto tetDim = 3 ;
228+ const auto edgeDim = 1 ;
229+ const auto tetToEdgeDegree = Omega_h::simplex_degree (tetDim, edgeDim);
230+ osh_ent = tetEdges[(tet * tetToEdgeDegree) + dofHolderIdx];
231+ } else {
232+ assert (false );
233+ }
234+ return {0 , tetCompIdx, osh_ent, dofHolderTopo};
235+ }
236+ };
237+
154238template <int ShapeOrder> auto getTriangleElement (Omega_h::Mesh &mesh) {
155239 static_assert (ShapeOrder == 1 || ShapeOrder == 2 );
156240 if constexpr (ShapeOrder == 1 ) {
@@ -169,6 +253,24 @@ template <int ShapeOrder> auto getTriangleElement(Omega_h::Mesh &mesh) {
169253 QuadraticTriangleToField (mesh)};
170254 }
171255}
256+ template <int ShapeOrder> auto getTetrahedronElement (Omega_h::Mesh &mesh) {
257+ static_assert (ShapeOrder == 1 || ShapeOrder == 2 );
258+ if constexpr (ShapeOrder == 1 ) {
259+ struct result {
260+ MeshField::LinearTetrahedronShape shp;
261+ LinearTetrahedronToVertexField map;
262+ };
263+ return result{MeshField::LinearTetrahedronShape (),
264+ LinearTetrahedronToVertexField (mesh)};
265+ } else if constexpr (ShapeOrder == 2 ) {
266+ struct result {
267+ MeshField::QuadraticTetrahedronShape shp;
268+ QuadraticTetrahedronToField map;
269+ };
270+ return result{MeshField::QuadraticTetrahedronShape (),
271+ QuadraticTetrahedronToField (mesh)};
272+ }
273+ }
172274
173275} // namespace Omegah
174276
@@ -252,6 +354,32 @@ class OmegahMeshField {
252354 auto eval = MeshField::evaluate (f, localCoords, offsets);
253355 return eval;
254356 }
357+
358+ template <typename ViewType, typename ShapeField>
359+ auto tetrahedronLocalPointEval (ViewType localCoords, size_t NumPtsPerElem,
360+ ShapeField field) {
361+ auto offsets = createOffsets (meshInfo.numTet , NumPtsPerElem);
362+ auto eval = tetrahedronLocalPointEval (localCoords, offsets, field);
363+ return eval;
364+ }
365+
366+ template <typename ViewType, typename ShapeField>
367+ auto tetrahedronLocalPointEval (ViewType localCoords,
368+ Kokkos::View<LO *> offsets, ShapeField field) {
369+ const auto MeshDim = 3 ;
370+ if (mesh.dim () != MeshDim) {
371+ MeshField::fail (" input mesh must be 3d\n " );
372+ }
373+ const auto ShapeOrder = ShapeField::Order;
374+ if (ShapeOrder != 1 && ShapeOrder != 2 ) {
375+ MeshField::fail (" input field order must be 1 or 2\n " );
376+ }
377+ const auto [shp, map] = Omegah::getTetrahedronElement<ShapeOrder>(mesh);
378+ MeshField::FieldElement<ShapeField, decltype (shp), decltype (map)> f (
379+ meshInfo.numTet , field, shp, map);
380+ auto eval = MeshField::evaluate (f, localCoords, offsets);
381+ return eval;
382+ }
255383};
256384
257385} // namespace MeshField
0 commit comments