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 <
int dim,
typename Field,
typename Coords,
typename CoordinateMap>
36 struct SetCoordFieldFunctor
38 SetCoordFieldFunctor(Field& field, Coords& coords,
int meshDim,
39 const CoordinateMap& map) :
40 field_(field), coords_(coords), meshDim_(meshDim), map_(map) {}
41 KOKKOS_INLINE_FUNCTION
42 void operator()(
const size_t vtx)
const {
43 Kokkos::Array<MeshField::Real, dim> x{};
44 for (
int d = 0; d < meshDim_; ++d)
45 x[d] = coords_[vtx * meshDim_ + d];
46 const auto mapped = map_(x);
47 for (
int d = 0; d < meshDim_; ++d)
48 field_(vtx, 0, d, MeshField::Vertex) = mapped[d];
53 const CoordinateMap map_;
57 template <
int dim,
typename Element,
typename CoordinateMap>
58 struct InterpolateElementFunctor
60 InterpolateElementFunctor(
const Element& element,
const CoordinateMap& map)
61 : element_(element), map_(map) {}
63 KOKKOS_INLINE_FUNCTION
64 auto operator()(
const int ent, Kokkos::Array<MeshField::Real, dim>
const& xi)
const {
65 return map_(element_.getValue(ent, xi));
68 const Element element_;
69 const CoordinateMap map_;
77 struct LinearTriangleToVertexField {
78 Omega_h::LOs triVerts;
79 LinearTriangleToVertexField(Omega_h::Mesh &mesh)
80 : triVerts(mesh.ask_elem_verts()) {
81 if (mesh.dim() != 2 && mesh.family() != OMEGA_H_SIMPLEX) {
83 "The mesh passed to %s must be 2D and simplex (triangles)\n",
88 static constexpr KOKKOS_FUNCTION Kokkos::Array<MeshField::Mesh_Topology, 1>
90 return {MeshField::Triangle};
94 operator()(MeshField::LO triNodeIdx, MeshField::LO triCompIdx,
95 MeshField::LO tri, MeshField::Mesh_Topology topo)
const {
96 assert(topo == MeshField::Triangle);
97 const auto triDim = 2;
98 const auto vtxDim = 0;
99 const auto ignored = -1;
100 const auto localVtxIdx =
101 Omega_h::simplex_down_template(triDim, vtxDim, triNodeIdx, ignored);
102 const auto triToVtxDegree = Omega_h::simplex_degree(triDim, vtxDim);
103 const MeshField::LO vtx = triVerts[(tri * triToVtxDegree) + localVtxIdx];
104 return {0, triCompIdx, vtx, MeshField::Vertex};
107 struct LinearTetrahedronToVertexField {
108 Omega_h::LOs tetVerts;
109 LinearTetrahedronToVertexField(Omega_h::Mesh &mesh)
110 : tetVerts(mesh.ask_elem_verts()) {
111 if (mesh.dim() != 3 && mesh.family() != OMEGA_H_SIMPLEX) {
113 "The mesh passed to %s must be 3D and simplex (tetrahedron)\n",
117 static constexpr KOKKOS_FUNCTION Kokkos::Array<MeshField::Mesh_Topology, 1>
119 return {MeshField::Tetrahedron};
123 operator()(MeshField::LO tetNodeIdx, MeshField::LO tetCompIdx,
124 MeshField::LO tet, MeshField::Mesh_Topology topo)
const {
125 assert(topo == MeshField::Tetrahedron);
126 const auto tetDim = 3;
127 const auto vtxDim = 0;
128 const auto ignored = -1;
129 const auto localVtxIdx = Omega_h::simplex_down_template(tetDim, vtxDim, tetNodeIdx, ignored);
130 const auto tetToVtxDegree = Omega_h::simplex_degree(tetDim, vtxDim);
131 const MeshField::LO vtx = tetVerts[(tet * tetToVtxDegree) + localVtxIdx];
132 return {0, tetCompIdx, vtx, MeshField::Vertex};
137 Omega_h::LOs triVerts;
138 Omega_h::LOs triEdges;
140 : triVerts(mesh.ask_elem_verts()),
141 triEdges(mesh.ask_down(mesh.dim(), 1).ab2b) {
142 if (mesh.dim() != 2 && mesh.family() != OMEGA_H_SIMPLEX) {
144 "The mesh passed to %s must be 2D and simplex (triangles)\n",
149 static constexpr KOKKOS_FUNCTION Kokkos::Array<MeshField::Mesh_Topology, 1>
151 return {MeshField::Triangle};
155 operator()(MeshField::LO triNodeIdx, MeshField::LO triCompIdx,
156 MeshField::LO tri, MeshField::Mesh_Topology topo)
const {
157 assert(topo == MeshField::Triangle);
160 const MeshField::LO triNode2DofHolder[6] = {
163 const MeshField::Mesh_Topology triNode2DofHolderTopo[6] = {
165 MeshField::Vertex, MeshField::Vertex, MeshField::Vertex,
167 MeshField::Edge, MeshField::Edge, MeshField::Edge};
168 const auto dofHolderIdx = triNode2DofHolder[triNodeIdx];
169 const auto dofHolderTopo = triNode2DofHolderTopo[triNodeIdx];
173 if (dofHolderTopo == MeshField::Vertex) {
174 const auto triDim = 2;
175 const auto vtxDim = 0;
176 const auto ignored = -1;
177 const auto localVtxIdx = Omega_h::simplex_down_template(
178 triDim, vtxDim, dofHolderIdx, ignored);
179 const auto triToVtxDegree = Omega_h::simplex_degree(triDim, vtxDim);
180 osh_ent = triVerts[(tri * triToVtxDegree) + localVtxIdx];
181 }
else if (dofHolderTopo == MeshField::Edge) {
182 const auto triDim = 2;
183 const auto edgeDim = 1;
184 const auto triToEdgeDegree = Omega_h::simplex_degree(triDim, edgeDim);
188 osh_ent = triEdges[(tri * triToEdgeDegree) + dofHolderIdx];
192 return {0, triCompIdx, osh_ent, dofHolderTopo};
198 Omega_h::LOs tetVerts;
199 Omega_h::LOs tetEdges;
201 : tetVerts(mesh.ask_elem_verts()),
202 tetEdges(mesh.ask_down(mesh.dim(), 1).ab2b) {
203 if (mesh.dim() != 3 && mesh.family() != OMEGA_H_SIMPLEX) {
205 "The mesh passed to %s must be 3D and simplex (tetrahedron)",
210 static constexpr KOKKOS_FUNCTION Kokkos::Array<MeshField::Mesh_Topology, 1>
212 return {MeshField::Tetrahedron};
216 operator()(MeshField::LO tetNodeIdx, MeshField::LO tetCompIdx,
217 MeshField::LO tet, MeshField::Mesh_Topology topo)
const {
218 assert(topo == MeshField::Tetrahedron);
219 const MeshField::LO tetNode2DofHolder[10] = {0, 1, 2, 3, 0, 2, 3, 1, 5, 4};
220 const MeshField::Mesh_Topology tetNode2DofHolderTopo[10] = {
221 MeshField::Vertex, MeshField::Vertex, MeshField::Vertex,
222 MeshField::Vertex, MeshField::Edge, MeshField::Edge,
223 MeshField::Edge, MeshField::Edge, MeshField::Edge,
225 const auto dofHolderIdx = tetNode2DofHolder[tetNodeIdx];
226 const auto dofHolderTopo = tetNode2DofHolderTopo[tetNodeIdx];
228 if (dofHolderTopo == MeshField::Vertex) {
229 const auto tetDim = 3;
230 const auto vtxDim = 0;
231 const auto ignored = -1;
232 const auto localVtxIdx = Omega_h::simplex_down_template(
233 tetDim, vtxDim, dofHolderIdx, ignored);
234 const auto tetToVtxDegree = Omega_h::simplex_degree(tetDim, vtxDim);
235 osh_ent = tetVerts[(tet * tetToVtxDegree) + localVtxIdx];
236 }
else if (dofHolderTopo == MeshField::Edge) {
237 const auto tetDim = 3;
238 const auto edgeDim = 1;
239 const auto tetToEdgeDegree = Omega_h::simplex_degree(tetDim, edgeDim);
240 osh_ent = tetEdges[(tet * tetToEdgeDegree) + dofHolderIdx];
244 return {0, tetCompIdx, osh_ent, dofHolderTopo};
249 template <
int ShapeOrder>
auto getTriangleElement(Omega_h::Mesh &mesh) {
250 static_assert(ShapeOrder == 1 || ShapeOrder == 2);
251 if constexpr (ShapeOrder == 1) {
254 LinearTriangleToVertexField map;
257 LinearTriangleToVertexField(mesh)};
258 }
else if constexpr (ShapeOrder == 2) {
261 QuadraticTriangleToField map;
264 QuadraticTriangleToField(mesh)};
268 template <
int ShapeOrder>
auto getTetrahedronElement(Omega_h::Mesh &mesh) {
269 static_assert(ShapeOrder == 1 || ShapeOrder == 2);
270 if constexpr (ShapeOrder == 1) {
273 LinearTetrahedronToVertexField map;
276 LinearTetrahedronToVertexField(mesh)};
277 }
else if constexpr (ShapeOrder == 2) {
280 QuadraticTetrahedronToField map;
283 QuadraticTetrahedronToField(mesh)};
293 template <
typename Po
int>
294 KOKKOS_INLINE_FUNCTION Point operator()(Point
const &x)
const {
299 template <
typename ExecutionSpace,
size_t dim,
300 template <
typename...>
typename Controller =
301 MeshField::KokkosController>
302 class OmegahMeshField {
307 decltype(MeshField::CreateCoordinateField<ExecutionSpace, Controller,
309 CoordField coordField;
312 OmegahMeshField(Omega_h::Mesh &mesh_in)
313 : mesh(mesh_in), meshInfo(getMeshInfo(mesh)),
314 coordField(CreateLagrangeCoordinateField<1>()) {
315 static_assert(dim == 1 || dim == 2 || dim == 3);
318 template <
typename DataType,
size_t order,
size_t numComp>
320 auto CreateLagrangeField()
const {
321 return MeshField::CreateLagrangeField<ExecutionSpace, Controller, DataType,
322 order, dim, numComp>(meshInfo);
340 template <
size_t order,
typename CoordinateMap = IdentityCoordinateMap>
341 auto CreateLagrangeCoordinateField(
342 const CoordinateMap &map = CoordinateMap())
const {
343 auto fieldWithCtrlr = CreateLagrangeField<Real, order, dim>();
344 auto field = fieldWithCtrlr.field;
347 if constexpr (order == 1) {
348 const auto meshDim = meshInfo.dim;
349 const auto coords = mesh.coords();
350 MeshField::parallel_for<decltype(fieldWithCtrlr.ctrlr)>(
351 {0}, {meshInfo.numVtx},
352 SetCoordFieldFunctor<dim, decltype(field), decltype(coords),
353 CoordinateMap>(field, coords, meshDim, map),
356 const auto linear = CreateLagrangeElement(coordField.field);
357 auto target = CreateLagrangeElement(field);
358 MeshField::setDofByInterpolation(
360 InterpolateElementFunctor<dim, decltype(linear), CoordinateMap>(
363 return fieldWithCtrlr;
366 auto getCoordField() {
return coordField; }
372 template <
typename Field>
373 auto CreateLagrangeElement(
const Field &field)
const {
374 static_assert(dim == 2 || dim == 3,
375 "CreateLagrangeElement supports triangles and tetrahedra");
376 constexpr
int order = Field::Order;
377 if constexpr (dim == 2) {
378 const auto [shp, map] = Omegah::getTriangleElement<order>(mesh);
381 const auto [shp, map] = Omegah::getTetrahedronElement<order>(mesh);
387 template <
typename Field>
void writeVtk(Field &field)
const {
388 using FieldDataType =
typename decltype(field.vtxField)::BaseType;
390 auto field_view = field.vtxField.serialize();
391 Omega_h::Write<FieldDataType> field_write(field_view);
392 mesh.add_tag(0,
"field", 1, Omega_h::read(field_write),
false,
393 Omega_h::ArrayType::VectorND);
394 Omega_h::vtk::write_parallel(
"foo.vtk", &mesh, mesh.dim());
397 template <
typename ViewType = Kokkos::View<MeshField::LO *>>
398 ViewType createOffsets(
size_t numTri,
size_t numPtsPerElem)
const {
399 ViewType offsets(
"offsets", numTri + 1);
400 Kokkos::parallel_for(
401 "setOffsets", numTri,
402 KOKKOS_LAMBDA(
int i) { offsets(i) = i * numPtsPerElem; });
403 Kokkos::deep_copy(Kokkos::subview(offsets, offsets.size() - 1),
404 numTri * numPtsPerElem);
409 template <
typename ViewType,
typename ShapeField>
410 auto triangleLocalPointEval(
const ViewType &localCoords,
size_t NumPtsPerElem,
411 const ShapeField &field)
const {
412 auto offsets = createOffsets(meshInfo.numTri, NumPtsPerElem);
413 auto eval = triangleLocalPointEval<ViewType, ShapeField>(localCoords,
419 template <
typename ViewType,
typename ShapeField>
420 auto triangleLocalPointEval(
const ViewType &localCoords,
421 Kokkos::View<LO *> offsets,
422 const ShapeField &field)
const {
423 const auto MeshDim = 2;
424 if (mesh.dim() != MeshDim) {
425 MeshField::fail(
"input mesh must be 2d\n");
427 const auto ShapeOrder = ShapeField::Order;
428 if (ShapeOrder != 1 && ShapeOrder != 2) {
429 MeshField::fail(
"input field order must be 1 or 2\n");
432 const auto [shp, map] = Omegah::getTriangleElement<ShapeOrder>(mesh);
435 meshInfo.numTri, field, shp, map);
436 auto eval = MeshField::evaluate(f, localCoords, offsets);
440 template <
typename ViewType,
typename ShapeField>
441 auto tetrahedronLocalPointEval(
const ViewType &localCoords,
442 size_t NumPtsPerElem,
443 const ShapeField &field)
const {
444 auto offsets = createOffsets(meshInfo.numTet, NumPtsPerElem);
445 auto eval = tetrahedronLocalPointEval(localCoords, offsets, field);
449 template <
typename ViewType,
typename ShapeField>
450 auto tetrahedronLocalPointEval(
const ViewType &localCoords,
451 Kokkos::View<LO *> offsets,
452 const ShapeField &field)
const {
453 const auto MeshDim = 3;
454 if (mesh.dim() != MeshDim) {
455 MeshField::fail(
"input mesh must be 3d\n");
457 const auto ShapeOrder = ShapeField::Order;
458 if (ShapeOrder != 1 && ShapeOrder != 2) {
459 MeshField::fail(
"input field order must be 1 or 2\n");
461 const auto [shp, map] = Omegah::getTetrahedronElement<ShapeOrder>(mesh);
463 meshInfo.numTet, field, shp, map);
464 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...
the CoordinateMap that leaves the mesh geometry unchanged
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.