1 #include "serac/numerics/functional/element_restriction.hpp"
5 #include "serac/numerics/functional/geometry.hpp"
7 std::vector<std::vector<int> > lexicographic_permutations(
int p)
15 std::vector<std::vector<int> > output(mfem::Geometry::Type::NUM_GEOMETRIES);
18 auto P = mfem::H1_SegmentElement(p).GetLexicographicOrdering();
19 std::vector<int> native_to_lex(uint32_t(P.Size()));
20 for (
int i = 0; i < P.Size(); i++) {
21 native_to_lex[uint32_t(i)] = P[i];
23 output[mfem::Geometry::Type::SEGMENT] = native_to_lex;
27 auto P = mfem::H1_TriangleElement(p).GetLexicographicOrdering();
28 std::vector<int> native_to_lex(uint32_t(P.Size()));
29 for (
int i = 0; i < P.Size(); i++) {
30 native_to_lex[uint32_t(i)] = P[i];
32 output[mfem::Geometry::Type::TRIANGLE] = native_to_lex;
36 auto P = mfem::H1_QuadrilateralElement(p).GetLexicographicOrdering();
37 std::vector<int> native_to_lex(uint32_t(P.Size()));
38 for (
int i = 0; i < P.Size(); i++) {
39 native_to_lex[uint32_t(i)] = P[i];
41 output[mfem::Geometry::Type::SQUARE] = native_to_lex;
45 auto P = mfem::H1_TetrahedronElement(p).GetLexicographicOrdering();
46 std::vector<int> native_to_lex(uint32_t(P.Size()));
47 for (
int i = 0; i < P.Size(); i++) {
48 native_to_lex[uint32_t(i)] = P[i];
50 output[mfem::Geometry::Type::TETRAHEDRON] = native_to_lex;
54 auto P = mfem::H1_HexahedronElement(p).GetLexicographicOrdering();
55 std::vector<int> native_to_lex(uint32_t(P.Size()));
56 for (
int i = 0; i < P.Size(); i++) {
57 native_to_lex[uint32_t(i)] = P[i];
59 output[mfem::Geometry::Type::CUBE] = native_to_lex;
67 Array2D<int> face_permutations(mfem::Geometry::Type geom,
int p)
69 if (geom == mfem::Geometry::Type::SEGMENT) {
71 for (
int i = 0; i <= p; i++) {
78 if (geom == mfem::Geometry::Type::TRIANGLE) {
85 auto tri_id = [p](
int x,
int y) {
return x + ((3 + 2 * p - y) * y) / 2; };
86 for (
int j = 0; j <= p; j++) {
87 for (
int i = 0; i <= p - j; i++) {
88 int id = tri_id(i, j);
89 output(0, tri_id(i, j)) = id;
90 output(1, tri_id(p - i - j, j)) = id;
91 output(2, tri_id(j, p - i - j)) = id;
92 output(3, tri_id(i, p - i - j)) = id;
93 output(4, tri_id(p - i - j, i)) = id;
94 output(5, tri_id(j, i)) = id;
100 if (geom == mfem::Geometry::Type::SQUARE) {
108 auto quad_id = [p](
int x,
int y) {
return ((p + 1) * y) + x; };
109 for (
int j = 0; j <= p; j++) {
110 for (
int i = 0; i <= p; i++) {
111 int id = quad_id(i, j);
112 output(0, quad_id(i, j)) = id;
113 output(1, quad_id(j, i)) = id;
114 output(2, quad_id(p - j, i)) = id;
115 output(3, quad_id(p - i, j)) = id;
116 output(4, quad_id(p - i, p - j)) = id;
117 output(5, quad_id(p - j, p - i)) = id;
118 output(6, quad_id(j, p - i)) = id;
119 output(7, quad_id(i, p - j)) = id;
125 std::cout <<
"face_permutation(): unsupported geometry type" << std::endl;
129 std::vector<Array2D<int> > geom_local_face_dofs(
int p)
138 auto tri_id = [p](
int x,
int y) {
return x + ((3 + 2 * p - y) * y) / 2; };
148 auto tet_id = [p](
int x,
int y,
int z) {
149 return x + (z * (11 + p * (12 + 3 * p) - 6 * y + z * (z - 6 - 3 * p)) - 3 * y * (y - 2 * p - 3)) / 6;
152 auto quad_id = [p](
int x,
int y) {
return ((p + 1) * y) + x; };
154 auto hex_id = [p](
int x,
int y,
int z) {
return (p + 1) * ((p + 1) * z + y) + x; };
156 std::vector<Array2D<int> > output(mfem::Geometry::Type::NUM_GEOMETRIES);
159 for (
int k = 0; k <= p; k++) {
160 tris(0, k) = tri_id(k, 0);
161 tris(1, k) = tri_id(p - k, k);
162 tris(2, k) = tri_id(0, p - k);
164 output[mfem::Geometry::Type::TRIANGLE] = tris;
167 for (
int k = 0; k <= p; k++) {
168 quads(0, k) = quad_id(k, 0);
169 quads(1, k) = quad_id(p, k);
170 quads(2, k) = quad_id(p - k, p);
171 quads(3, k) = quad_id(0, p - k);
173 output[mfem::Geometry::Type::SQUARE] = quads;
181 for (
int k = 0; k <= p; k++) {
182 for (
int j = 0; j <= p - k; j++) {
183 int id = tri_id(j, k);
184 tets(0,
id) = tet_id(p - j - k, j, k);
185 tets(1,
id) = tet_id(0, k, j);
186 tets(2,
id) = tet_id(j, 0, k);
187 tets(3,
id) = tet_id(k, j, 0);
190 output[mfem::Geometry::Type::TETRAHEDRON] = tets;
200 for (
int k = 0; k <= p; k++) {
201 for (
int j = 0; j <= p; j++) {
202 int id = quad_id(j, k);
203 hexes(0,
id) = hex_id(j, p - k, 0);
204 hexes(1,
id) = hex_id(j, 0, k);
205 hexes(2,
id) = hex_id(p, j, k);
206 hexes(3,
id) = hex_id(p - j, p, k);
207 hexes(4,
id) = hex_id(0, p - j, k);
208 hexes(5,
id) = hex_id(j, k, p);
211 output[mfem::Geometry::Type::CUBE] = hexes;
216 axom::Array<DoF, 2, axom::MemorySpace::Host> GetElementRestriction(
const mfem::FiniteElementSpace* fes,
217 mfem::Geometry::Type geom)
219 std::vector<DoF> elem_dofs{};
220 mfem::Mesh* mesh = fes->GetMesh();
223 int p = fes->GetElementOrder(0);
224 std::vector<std::vector<int> > lex_perm = lexicographic_permutations(p);
228 for (
int elem = 0; elem < fes->GetNE(); elem++) {
230 if (mesh->GetElementGeometry(elem) != geom)
continue;
232 mfem::Array<int> dofs;
234 [[maybe_unused]]
auto* dof_transformation = fes->GetElementDofs(elem, dofs);
239 for (
int k = 0; k < dofs.Size(); k++) {
240 elem_dofs.push_back({uint64_t(dofs[lex_perm[uint32_t(geom)][uint32_t(k)]])});
252 uint64_t orientation = 0;
253 for (
int k = 0; k < dofs.Size(); k++) {
254 elem_dofs.push_back({uint64_t(dofs[k]), sign, orientation});
261 for (
int k = 0; k < dofs.Size(); k++) {
262 elem_dofs.push_back({uint64_t(dofs[k])});
270 return axom::Array<DoF, 2, axom::MemorySpace::Host>{};
272 uint64_t dofs_per_elem = elem_dofs.size() / n;
273 axom::Array<DoF, 2, axom::MemorySpace::Host> output(n, dofs_per_elem);
274 std::memcpy(output.data(), elem_dofs.data(),
sizeof(
DoF) * n * dofs_per_elem);
279 axom::Array<DoF, 2, axom::MemorySpace::Host> GetFaceDofs(
const mfem::FiniteElementSpace* fes,
280 mfem::Geometry::Type face_geom, FaceType
type)
282 std::vector<DoF> face_dofs;
283 mfem::Mesh* mesh = fes->GetMesh();
284 mfem::Table* face_to_elem = mesh->GetFaceToElementTable();
287 int p = fes->GetElementOrder(0);
288 Array2D<int> face_perm = face_permutations(face_geom, p);
289 std::vector<Array2D<int> > local_face_dofs = geom_local_face_dofs(p);
290 std::vector<std::vector<int> > lex_perm = lexicographic_permutations(p);
294 for (
int f = 0; f < fes->GetNF(); f++) {
295 auto faceinfo = mesh->GetFaceInformation(f);
298 if (mesh->GetFaceGeometry(f) != face_geom)
continue;
299 if (faceinfo.IsInterior() &&
type == FaceType::BOUNDARY)
continue;
300 if (faceinfo.IsBoundary() &&
type == FaceType::INTERIOR)
continue;
306 mfem::Array<int> elem_ids;
307 face_to_elem->GetRow(f, elem_ids);
309 for (
auto elem : elem_ids) {
311 mfem::Array<int> elem_side_ids, orientations;
312 if (mesh->Dimension() == 2) {
313 mesh->GetElementEdges(elem, elem_side_ids, orientations);
320 for (
auto& o : orientations) {
321 o = (o == -1) ? 1 : 0;
325 mesh->GetElementFaces(elem, elem_side_ids, orientations);
330 for (i = 0; i < elem_side_ids.Size(); i++) {
331 if (elem_side_ids[i] == f)
break;
335 mfem::Array<int> elem_dof_ids;
336 fes->GetElementDofs(elem, elem_dof_ids);
338 mfem::Geometry::Type elem_geom = mesh->GetElementGeometry(elem);
346 int orientation = (mesh->Dimension() == 2 &&
type == FaceType::BOUNDARY) ? 0 : orientations[i];
349 for (
auto k : face_perm(orientation)) {
350 face_dofs.push_back(uint64_t(elem_dof_ids[local_face_dofs[uint32_t(elem_geom)](i, k)]));
354 if (
type == FaceType::BOUNDARY)
break;
360 mfem::Array<int> dofs;
362 fes->GetFaceDofs(f, dofs);
365 for (
int k = 0; k < dofs.Size(); k++) {
366 face_dofs.push_back(uint64_t(dofs[k]));
369 for (
int k = 0; k < dofs.Size(); k++) {
370 face_dofs.push_back(uint64_t(dofs[lex_perm[uint32_t(face_geom)][uint32_t(k)]]));
381 return axom::Array<DoF, 2, axom::MemorySpace::Host>{};
383 uint64_t dofs_per_face = face_dofs.size() / n;
384 axom::Array<DoF, 2, axom::MemorySpace::Host> output(n, dofs_per_face);
385 std::memcpy(output.data(), face_dofs.data(),
sizeof(
DoF) * n * dofs_per_face);
394 dof_info = GetElementRestriction(fes, elem_geom);
398 lsize = uint64_t(fes->GetVSize());
413 lsize = uint64_t(fes->GetVSize());
427 if (
ordering == mfem::Ordering::Type::byNODES) {
450 E_vector[int(E_id)] = L_vector[int(L_id)];
463 L_vector[int(L_id)] += E_vector[int(E_id)];
473 int dim = fes->GetMesh()->Dimension();
476 for (
auto geom : {mfem::Geometry::TRIANGLE, mfem::Geometry::SQUARE}) {
482 for (
auto geom : {mfem::Geometry::TETRAHEDRON, mfem::Geometry::CUBE}) {
490 int dim = fes->GetMesh()->Dimension();
497 for (
auto geom : {mfem::Geometry::TRIANGLE, mfem::Geometry::SQUARE}) {
509 mfem::Array<int> offsets(mfem::Geometry::NUM_GEOMETRIES + 1);
512 for (
int i = 0; i < mfem::Geometry::NUM_GEOMETRIES; i++) {
513 auto g = mfem::Geometry::Type(i);
515 offsets[g + 1] = offsets[g] + int(
restrictions.at(g).ESize());
517 offsets[g + 1] = offsets[g];
527 restriction.Gather(L_vector, E_block_vector.GetBlock(geom));
534 restriction.ScatterAdd(E_block_vector.GetBlock(geom), L_vector);
Accelerator functionality.
bool isHcurl(const mfem::ParFiniteElementSpace &fes)
return whether or not the underlying function space is Hcurl or not
constexpr SERAC_HOST_DEVICE auto type(const tuple< T... > &values)
a function intended to be used for extracting the ith type from a tuple.
a struct of metadata (index, sign, orientation) associated with a degree of freedom
int sign() const
get the sign field of this DoF
uint64_t index() const
get the index field of this DoF
uint64_t orientation() const
get the orientation field of this DoF
BlockElementRestriction()
default ctor leaves this object uninitialized
mfem::Array< int > bOffsets() const
block offsets used when constructing mfem::HypreParVectors
void ScatterAdd(const mfem::BlockVector &E_block_vector, mfem::Vector &L_vector) const
"E->L" in mfem parlance, each element scatter-adds its local vector into the appropriate place in the...
uint64_t ESize() const
the size of the "E-vector" associated with this restriction operator
std::map< mfem::Geometry::Type, ElementRestriction > restrictions
the individual ElementRestriction operators for each element geometry
void Gather(const mfem::Vector &L_vector, mfem::BlockVector &E_block_vector) const
"L->E" in mfem parlance, each element gathers the values that belong to it, and stores them in the "E...
uint64_t LSize() const
the size of the "L-vector" associated with this restriction operator
mfem::Ordering::Type ordering
whether the underlying dofs are arranged "byNodes" or "byVDim"
uint64_t num_nodes
the total number of nodes in the mesh
ElementRestriction()
default ctor leaves this object uninitialized
uint64_t nodes_per_elem
the number of nodes in each element
uint64_t lsize
the size of the "L-vector"
void GetElementVDofs(int i, std::vector< DoF > &dofs) const
Get a list of DoFs for element i
axom::Array< DoF, 2, axom::MemorySpace::Host > dof_info
a 2D array (num_elements-by-nodes_per_elem) holding the dof info extracted from the finite element sp...
void ScatterAdd(const mfem::Vector &E_vector, mfem::Vector &L_vector) const
"E->L" in mfem parlance, each element scatter-adds its local vector into the appropriate place in the...
uint64_t esize
the size of the "E-vector"
uint64_t num_elements
the number of elements of the given geometry
uint64_t components
the number of components at each node
void Gather(const mfem::Vector &L_vector, mfem::Vector &E_vector) const
"L->E" in mfem parlance, each element gathers the values that belong to it, and stores them in the "E...
uint64_t LSize() const
the size of the "L-vector" associated with this restriction operator
uint64_t ESize() const
the size of the "E-vector" associated with this restriction operator
DoF GetVDof(DoF node, uint64_t component) const
get the dof information for a given node / component