|
| 1 | +#include <Kokkos_Core.hpp> |
| 2 | +#include <MeshField.hpp> |
| 3 | +#include <Omega_h_build.hpp> |
| 4 | +#include <Omega_h_mesh.hpp> |
| 5 | +template <size_t order> void runTest(Omega_h::Mesh mesh) { |
| 6 | + MeshField::OmegahMeshField<Kokkos::DefaultExecutionSpace, 2> mesh_field(mesh); |
| 7 | + auto shape_field = |
| 8 | + mesh_field.template CreateLagrangeField<double, order, 1>(); |
| 9 | + |
| 10 | + // initialize vertices |
| 11 | + auto dim = mesh.dim(); |
| 12 | + auto coords = mesh.coords(); |
| 13 | + auto f = KOKKOS_LAMBDA(double x, double y)->double { return 2 * x + 3 * y; }; |
| 14 | + auto edge2vtx = mesh.ask_down(1, 0).ab2b; |
| 15 | + auto edgeMap = mesh.ask_down(dim, 1).ab2b; |
| 16 | + Kokkos::parallel_for( |
| 17 | + mesh.nverts(), KOKKOS_LAMBDA(int vtx) { |
| 18 | + auto x = coords[vtx * dim]; |
| 19 | + auto y = coords[vtx * dim + 1]; |
| 20 | + shape_field(vtx, 0, 0, MeshField::Mesh_Topology::Vertex) = f(x, y); |
| 21 | + }); |
| 22 | + if (order == 2) { |
| 23 | + Kokkos::parallel_for( |
| 24 | + mesh.nedges(), KOKKOS_LAMBDA(int edge) { |
| 25 | + const auto left = edge2vtx[edge * 2]; |
| 26 | + const auto right = edge2vtx[edge * 2 + 1]; |
| 27 | + const auto x = (coords[left * dim] + coords[right * dim]) / 2.0; |
| 28 | + const auto y = |
| 29 | + (coords[left * dim + 1] + coords[right * dim + 1]) / 2.0; |
| 30 | + shape_field(edge, 0, 0, MeshField::Mesh_Topology::Edge) = f(x, y); |
| 31 | + }); |
| 32 | + } |
| 33 | + const auto numNodesPerElem = order == 2 ? 6 : 3; |
| 34 | + Kokkos::View<double **> local_coords("", mesh.nelems() * numNodesPerElem, 3); |
| 35 | + Kokkos::parallel_for( |
| 36 | + "set", mesh.nelems() * numNodesPerElem, KOKKOS_LAMBDA(const int &i) { |
| 37 | + const auto val = i % numNodesPerElem; |
| 38 | + local_coords(i, 0) = (val == 0); |
| 39 | + local_coords(i, 1) = (val == 1); |
| 40 | + local_coords(i, 2) = (val == 2); |
| 41 | + if constexpr (order == 2) { |
| 42 | + if (val == 3) { |
| 43 | + local_coords(i, 0) = 1 / 2.0; |
| 44 | + local_coords(i, 1) = 1 / 2.0; |
| 45 | + } else if (val == 4) { |
| 46 | + local_coords(i, 1) = 1 / 2.0; |
| 47 | + local_coords(i, 2) = 1 / 2.0; |
| 48 | + } else if (val == 5) { |
| 49 | + local_coords(i, 0) = 1 / 2.0; |
| 50 | + local_coords(i, 2) = 1 / 2.0; |
| 51 | + } |
| 52 | + } |
| 53 | + }); |
| 54 | + |
| 55 | + auto eval_results = mesh_field.triangleLocalPointEval( |
| 56 | + local_coords, numNodesPerElem, shape_field); |
| 57 | + |
| 58 | + int errors = 0; |
| 59 | + const auto triVerts = mesh.ask_elem_verts(); |
| 60 | + const auto coordField = mesh_field.getCoordField(); |
| 61 | + Kokkos::parallel_reduce( |
| 62 | + "test", mesh.nelems(), |
| 63 | + KOKKOS_LAMBDA(const int &tri, int &errors) { |
| 64 | + for (int node = 0; node < 3; ++node) { |
| 65 | + const auto triDim = 2; |
| 66 | + const auto vtxDim = 0; |
| 67 | + const auto ignored = -1; |
| 68 | + const auto localVtxIdx = |
| 69 | + Omega_h::simplex_down_template(triDim, vtxDim, node, ignored); |
| 70 | + const auto triToVtxDegree = Omega_h::simplex_degree(triDim, vtxDim); |
| 71 | + int vtx = triVerts[(tri * triToVtxDegree) + localVtxIdx]; |
| 72 | + auto x = coords[vtx * dim]; |
| 73 | + auto y = coords[vtx * dim + 1]; |
| 74 | + auto expected = f(x, y); |
| 75 | + auto actual = eval_results(tri * numNodesPerElem + node, 0); |
| 76 | + if (Kokkos::fabs(expected - actual) > MeshField::MachinePrecision) { |
| 77 | + ++errors; |
| 78 | + Kokkos::printf( |
| 79 | + "expected: %lf, actual: %lf, element: %d, node(vtx): %d\n", |
| 80 | + expected, actual, tri, node); |
| 81 | + } |
| 82 | + } |
| 83 | + for (int node = 3; node < numNodesPerElem; ++node) { |
| 84 | + const auto triDim = 2; |
| 85 | + const auto edgeDim = 1; |
| 86 | + const auto triToEdgeDegree = Omega_h::simplex_degree(triDim, edgeDim); |
| 87 | + const MeshField::LO triNode2DofHolder[3] = {0, 1, 2}; |
| 88 | + int edge = |
| 89 | + edgeMap[(tri * triToEdgeDegree) + triNode2DofHolder[node - 3]]; |
| 90 | + auto left = edge2vtx[edge * 2]; |
| 91 | + auto right = edge2vtx[edge * 2 + 1]; |
| 92 | + auto x = (coords[left * dim] + coords[right * dim]) / 2.0; |
| 93 | + auto y = (coords[left * dim + 1] + coords[right * dim + 1]) / 2.0; |
| 94 | + auto expected = f(x, y); |
| 95 | + auto actual = eval_results(tri * numNodesPerElem + node, 0); |
| 96 | + if (Kokkos::fabs(expected - actual) > MeshField::MachinePrecision) { |
| 97 | + ++errors; |
| 98 | + Kokkos::printf( |
| 99 | + "expected: %lf, actual: %lf, element: %d, node(edge): %d\n", |
| 100 | + expected, actual, tri, node); |
| 101 | + } |
| 102 | + } |
| 103 | + }, |
| 104 | + errors); |
| 105 | + if (errors > 0) { |
| 106 | + MeshField::fail("One or more mappings did not match\n"); |
| 107 | + } |
| 108 | +} |
| 109 | +int main(int argc, char **argv) { |
| 110 | + // setup |
| 111 | + Kokkos::initialize(argc, argv); |
| 112 | + auto lib = Omega_h::Library(&argc, &argv); |
| 113 | + { |
| 114 | + auto world = lib.world(); |
| 115 | + auto mesh = |
| 116 | + Omega_h::build_box(world, OMEGA_H_SIMPLEX, 1, 1, 1, 10, 10, 0, false); |
| 117 | + runTest<1>(mesh); |
| 118 | + runTest<2>(mesh); |
| 119 | + } |
| 120 | + Kokkos::finalize(); |
| 121 | + return 0; |
| 122 | +} |
0 commit comments