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 (
size_t d = 0; d < meshDim_; ++d)
45 x[d] = coords_[vtx * meshDim_ + d];
46 const auto mapped = map_(x);
47 for (
size_t d = 0; d < meshDim_; ++d)
48 field_(vtx, 0, d, MeshField::Vertex) = mapped[d];
53 const CoordinateMap map_;
56 template <
int dim,
typename Element,
typename CoordinateMap>
57 struct InterpolateElementFunctor
59 InterpolateElementFunctor(
const Element& element,
const CoordinateMap& map)
60 : element_(element), map_(map) {}
62 KOKKOS_INLINE_FUNCTION
63 auto operator()(
const int ent, Kokkos::Array<MeshField::Real, dim>
const& xi)
const {
64 return map_(element_.getValue(ent, xi));
67 const Element element_;
68 const CoordinateMap map_;
76 struct LinearTriangleToVertexField {
77 Omega_h::LOs triVerts;
78 LinearTriangleToVertexField(Omega_h::Mesh &mesh)
79 : triVerts(mesh.ask_elem_verts()) {
80 if (mesh.dim() != 2 && mesh.family() != OMEGA_H_SIMPLEX) {
82 "The mesh passed to %s must be 2D and simplex (triangles)\n",
87 static constexpr KOKKOS_FUNCTION Kokkos::Array<MeshField::Mesh_Topology, 1>
89 return {MeshField::Triangle};
93 operator()(MeshField::LO triNodeIdx, MeshField::LO triCompIdx,
94 MeshField::LO tri, MeshField::Mesh_Topology topo)
const {
95 assert(topo == MeshField::Triangle);
96 const auto triDim = 2;
97 const auto vtxDim = 0;
98 const auto ignored = -1;
99 const auto localVtxIdx =
100 (Omega_h::simplex_down_template(triDim, vtxDim, triNodeIdx, ignored) +
103 const auto triToVtxDegree = Omega_h::simplex_degree(triDim, vtxDim);
104 const MeshField::LO vtx = triVerts[(tri * triToVtxDegree) + localVtxIdx];
105 return {0, triCompIdx, vtx, MeshField::Vertex};
108 struct LinearTetrahedronToVertexField {
109 Omega_h::LOs tetVerts;
110 LinearTetrahedronToVertexField(Omega_h::Mesh &mesh)
111 : tetVerts(mesh.ask_elem_verts()) {
112 if (mesh.dim() != 3 && mesh.family() != OMEGA_H_SIMPLEX) {
114 "The mesh passed to %s must be 3D and simplex (tetrahedron)\n",
118 static constexpr KOKKOS_FUNCTION Kokkos::Array<MeshField::Mesh_Topology, 1>
120 return {MeshField::Tetrahedron};
124 operator()(MeshField::LO tetNodeIdx, MeshField::LO tetCompIdx,
125 MeshField::LO tet, MeshField::Mesh_Topology topo)
const {
126 assert(topo == MeshField::Tetrahedron);
127 const auto tetDim = 3;
128 const auto vtxDim = 0;
129 const auto ignored = -1;
130 const auto localVtxIdx =
131 (Omega_h::simplex_down_template(tetDim, vtxDim, tetNodeIdx, ignored) +
134 const auto tetToVtxDegree = Omega_h::simplex_degree(tetDim, vtxDim);
135 const MeshField::LO vtx = tetVerts[(tet * tetToVtxDegree) + localVtxIdx];
136 return {0, tetCompIdx, vtx, MeshField::Vertex};
141 Omega_h::LOs triVerts;
142 Omega_h::LOs triEdges;
144 : triVerts(mesh.ask_elem_verts()),
145 triEdges(mesh.ask_down(mesh.dim(), 1).ab2b) {
146 if (mesh.dim() != 2 && mesh.family() != OMEGA_H_SIMPLEX) {
148 "The mesh passed to %s must be 2D and simplex (triangles)\n",
153 static constexpr KOKKOS_FUNCTION Kokkos::Array<MeshField::Mesh_Topology, 1>
155 return {MeshField::Triangle};
159 operator()(MeshField::LO triNodeIdx, MeshField::LO triCompIdx,
160 MeshField::LO tri, MeshField::Mesh_Topology topo)
const {
161 assert(topo == MeshField::Triangle);
164 const MeshField::LO triNode2DofHolder[6] = {
167 const MeshField::Mesh_Topology triNode2DofHolderTopo[6] = {
169 MeshField::Vertex, MeshField::Vertex, MeshField::Vertex,
171 MeshField::Edge, MeshField::Edge, MeshField::Edge};
172 const auto dofHolderIdx = triNode2DofHolder[triNodeIdx];
173 const auto dofHolderTopo = triNode2DofHolderTopo[triNodeIdx];
177 if (dofHolderTopo == MeshField::Vertex) {
178 const auto triDim = 2;
179 const auto vtxDim = 0;
180 const auto ignored = -1;
181 const auto localVtxIdx = (Omega_h::simplex_down_template(
182 triDim, vtxDim, dofHolderIdx, ignored) +
185 const auto triToVtxDegree = Omega_h::simplex_degree(triDim, vtxDim);
186 osh_ent = triVerts[(tri * triToVtxDegree) + localVtxIdx];
187 }
else if (dofHolderTopo == MeshField::Edge) {
188 const auto triDim = 2;
189 const auto edgeDim = 1;
190 const auto triToEdgeDegree = Omega_h::simplex_degree(triDim, edgeDim);
194 osh_ent = triEdges[(tri * triToEdgeDegree) + (dofHolderIdx + 2) % 3];
198 return {0, triCompIdx, osh_ent, dofHolderTopo};
204 Omega_h::LOs tetVerts;
205 Omega_h::LOs tetEdges;
207 : tetVerts(mesh.ask_elem_verts()),
208 tetEdges(mesh.ask_down(mesh.dim(), 1).ab2b) {
209 if (mesh.dim() != 3 && mesh.family() != OMEGA_H_SIMPLEX) {
211 "The mesh passed to %s must be 3D and simplex (tetrahedron)",
216 static constexpr KOKKOS_FUNCTION Kokkos::Array<MeshField::Mesh_Topology, 1>
218 return {MeshField::Tetrahedron};
222 operator()(MeshField::LO tetNodeIdx, MeshField::LO tetCompIdx,
223 MeshField::LO tet, MeshField::Mesh_Topology topo)
const {
224 assert(topo == MeshField::Tetrahedron);
225 const MeshField::LO tetNode2DofHolder[10] = {0, 1, 2, 3, 3, 4, 5, 0, 1, 2};
226 const MeshField::Mesh_Topology tetNode2DofHolderTopo[10] = {
227 MeshField::Vertex, MeshField::Vertex, MeshField::Vertex,
228 MeshField::Vertex, MeshField::Edge, MeshField::Edge,
229 MeshField::Edge, MeshField::Edge, MeshField::Edge,
231 const auto dofHolderIdx = tetNode2DofHolder[tetNodeIdx];
232 const auto dofHolderTopo = tetNode2DofHolderTopo[tetNodeIdx];
234 if (dofHolderTopo == MeshField::Vertex) {
235 const auto tetDim = 3;
236 const auto vtxDim = 0;
237 const auto ignored = -1;
240 const auto localVtxIdx = (Omega_h::simplex_down_template(
241 tetDim, vtxDim, dofHolderIdx, ignored) +
244 const auto tetToVtxDegree = Omega_h::simplex_degree(tetDim, vtxDim);
245 osh_ent = tetVerts[(tet * tetToVtxDegree) + localVtxIdx];
246 }
else if (dofHolderTopo == MeshField::Edge) {
247 const auto tetDim = 3;
248 const auto edgeDim = 1;
249 const auto tetToEdgeDegree = Omega_h::simplex_degree(tetDim, edgeDim);
250 osh_ent = tetEdges[(tet * tetToEdgeDegree) + dofHolderIdx];
254 return {0, tetCompIdx, osh_ent, dofHolderTopo};
259 template <
int ShapeOrder>
auto getTriangleElement(Omega_h::Mesh &mesh) {
260 static_assert(ShapeOrder == 1 || ShapeOrder == 2);
261 if constexpr (ShapeOrder == 1) {
264 LinearTriangleToVertexField map;
267 LinearTriangleToVertexField(mesh)};
268 }
else if constexpr (ShapeOrder == 2) {
271 QuadraticTriangleToField map;
274 QuadraticTriangleToField(mesh)};
278 template <
int ShapeOrder>
auto getTetrahedronElement(Omega_h::Mesh &mesh) {
279 static_assert(ShapeOrder == 1 || ShapeOrder == 2);
280 if constexpr (ShapeOrder == 1) {
283 LinearTetrahedronToVertexField map;
286 LinearTetrahedronToVertexField(mesh)};
287 }
else if constexpr (ShapeOrder == 2) {
290 QuadraticTetrahedronToField map;
293 QuadraticTetrahedronToField(mesh)};
303 template <
typename Po
int>
304 KOKKOS_INLINE_FUNCTION Point operator()(Point
const &x)
const {
309 template <
typename ExecutionSpace,
size_t dim,
310 template <
typename...>
typename Controller =
311 MeshField::KokkosController>
312 class OmegahMeshField {
317 decltype(MeshField::CreateCoordinateField<ExecutionSpace, Controller,
319 CoordField coordField;
322 OmegahMeshField(Omega_h::Mesh &mesh_in)
323 : mesh(mesh_in), meshInfo(getMeshInfo(mesh)),
324 coordField(CreateLagrangeCoordinateField<1>()) {
325 static_assert(dim == 1 || dim == 2 || dim == 3);
328 template <
typename DataType,
size_t order,
size_t numComp>
330 auto CreateLagrangeField()
const {
331 return MeshField::CreateLagrangeField<ExecutionSpace, Controller, DataType,
332 order, dim, numComp>(meshInfo);
350 template <
size_t order,
typename CoordinateMap = IdentityCoordinateMap>
351 auto CreateLagrangeCoordinateField(
352 const CoordinateMap &map = CoordinateMap())
const {
353 auto fieldWithCtrlr = CreateLagrangeField<Real, order, dim>();
354 auto field = fieldWithCtrlr.field;
357 if constexpr (order == 1) {
358 const auto meshDim = meshInfo.dim;
359 const auto coords = mesh.coords();
360 MeshField::parallel_for(
361 ExecutionSpace(), {0}, {meshInfo.numVtx},
362 SetCoordFieldFunctor<dim, decltype(field), decltype(coords),
363 CoordinateMap>(field, coords, meshDim, map),
366 const auto linear = CreateLagrangeElement(coordField.field);
367 auto target = CreateLagrangeElement(field);
368 MeshField::setDofByInterpolation(
370 InterpolateElementFunctor<dim, decltype(linear), CoordinateMap>(
373 return fieldWithCtrlr;
376 auto getCoordField() {
return coordField; }
382 template <
typename Field>
383 auto CreateLagrangeElement(
const Field &field)
const {
384 static_assert(dim == 2 || dim == 3,
385 "CreateLagrangeElement supports triangles and tetrahedra");
386 constexpr
int order = Field::Order;
387 if constexpr (dim == 2) {
388 const auto [shp, map] = Omegah::getTriangleElement<order>(mesh);
391 const auto [shp, map] = Omegah::getTetrahedronElement<order>(mesh);
397 template <
typename Field>
void writeVtk(Field &field)
const {
398 using FieldDataType =
typename decltype(field.vtxField)::BaseType;
400 auto field_view = field.vtxField.serialize();
401 Omega_h::Write<FieldDataType> field_write(field_view);
402 mesh.add_tag(0,
"field", 1, Omega_h::read(field_write),
false,
403 Omega_h::ArrayType::VectorND);
404 Omega_h::vtk::write_parallel(
"foo.vtk", &mesh, mesh.dim());
407 template <
typename ViewType = Kokkos::View<MeshField::LO *>>
408 ViewType createOffsets(
size_t numTri,
size_t numPtsPerElem)
const {
409 ViewType offsets(
"offsets", numTri + 1);
410 Kokkos::parallel_for(
411 "setOffsets", numTri,
412 KOKKOS_LAMBDA(
int i) { offsets(i) = i * numPtsPerElem; });
413 Kokkos::deep_copy(Kokkos::subview(offsets, offsets.size() - 1),
414 numTri * numPtsPerElem);
419 template <
typename ViewType,
typename ShapeField>
420 auto triangleLocalPointEval(
const ViewType &localCoords,
size_t NumPtsPerElem,
421 const ShapeField &field)
const {
422 auto offsets = createOffsets(meshInfo.numTri, NumPtsPerElem);
423 auto eval = triangleLocalPointEval<ViewType, ShapeField>(localCoords,
429 template <
typename ViewType,
typename ShapeField>
430 auto triangleLocalPointEval(
const ViewType &localCoords,
431 Kokkos::View<LO *> offsets,
432 const ShapeField &field)
const {
433 const auto MeshDim = 2;
434 if (mesh.dim() != MeshDim) {
435 MeshField::fail(
"input mesh must be 2d\n");
437 const auto ShapeOrder = ShapeField::Order;
438 if (ShapeOrder != 1 && ShapeOrder != 2) {
439 MeshField::fail(
"input field order must be 1 or 2\n");
442 const auto [shp, map] = Omegah::getTriangleElement<ShapeOrder>(mesh);
445 meshInfo.numTri, field, shp, map);
446 auto eval = MeshField::evaluate(f, localCoords, offsets);
450 template <
typename ViewType,
typename ShapeField>
451 auto tetrahedronLocalPointEval(
const ViewType &localCoords,
452 size_t NumPtsPerElem,
453 const ShapeField &field)
const {
454 auto offsets = createOffsets(meshInfo.numTet, NumPtsPerElem);
455 auto eval = tetrahedronLocalPointEval(localCoords, offsets, field);
459 template <
typename ViewType,
typename ShapeField>
460 auto tetrahedronLocalPointEval(
const ViewType &localCoords,
461 Kokkos::View<LO *> offsets,
462 const ShapeField &field)
const {
463 const auto MeshDim = 3;
464 if (mesh.dim() != MeshDim) {
465 MeshField::fail(
"input mesh must be 3d\n");
467 const auto ShapeOrder = ShapeField::Order;
468 if (ShapeOrder != 1 && ShapeOrder != 2) {
469 MeshField::fail(
"input field order must be 1 or 2\n");
471 const auto [shp, map] = Omegah::getTetrahedronElement<ShapeOrder>(mesh);
473 meshInfo.numTet, field, shp, map);
474 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.