36 #include "serac/numerics/functional/element_restriction.hpp"
47 std::vector<tensor<double, d>>
gather(
const mfem::Vector& coordinates, mfem::Array<int> ids)
49 int num_vertices = coordinates.Size() / d;
50 std::vector<tensor<double, d>> x(std::size_t(ids.Size()));
51 for (
int v = 0; v < ids.Size(); v++) {
52 for (
int j = 0; j < d; j++) {
53 x[uint32_t(v)][j] = coordinates[j * num_vertices + ids[v]];
62 template <
int d,
typename T>
63 static Domain domain_of_edges(
const mesh_t& mesh, std::function<T> predicate)
65 assert(mesh.SpaceDimension() == d);
67 Domain output{mesh, 1 , Domain::Type::Elements};
71 mfem::Vector vertices;
72 mesh.GetVertices(vertices);
74 mfem::Array<int> edge_id_to_bdr_id;
76 edge_id_to_bdr_id = mesh.GetFaceToBdrElMap();
79 int num_edges = mesh.GetNEdges();
80 for (
int i = 0; i < num_edges; i++) {
81 mfem::Array<int> vertex_ids;
82 mesh.GetEdgeVertices(i, vertex_ids);
84 auto x = gather<d>(vertices, vertex_ids);
86 if constexpr (d == 2) {
87 int bdr_id = edge_id_to_bdr_id[i];
88 int attr = (bdr_id >= 0) ? mesh.GetBdrAttribute(bdr_id) : -1;
89 if (predicate(x, attr)) {
90 output.addElement(i, i, mfem::Geometry::SEGMENT);
94 output.addElement(i, i, mfem::Geometry::SEGMENT);
104 return domain_of_edges<2>(mesh, func);
109 return domain_of_edges<3>(mesh, func);
116 static Domain domain_of_faces(
const mesh_t& mesh, std::function<
bool(std::vector<
tensor<double, d>>,
int)> predicate)
118 assert(mesh.SpaceDimension() == d);
120 Domain output{mesh, 2 , Domain::Type::Elements};
124 mfem::Vector vertices;
125 mesh.GetVertices(vertices);
127 mfem::Array<int> face_id_to_bdr_id;
129 face_id_to_bdr_id = mesh.GetFaceToBdrElMap();
135 num_faces = mesh.GetNE();
137 num_faces = mesh.GetNumFaces();
143 for (
int i = 0; i < num_faces; i++) {
144 mfem::Array<int> vertex_ids;
146 if (mesh.Dimension() == 2) {
147 mesh.GetElementVertices(i, vertex_ids);
149 mesh.GetFaceVertices(i, vertex_ids);
152 auto x = gather<d>(vertices, vertex_ids);
156 attr = mesh.GetAttribute(i);
158 int bdr_id = face_id_to_bdr_id[i];
159 attr = (bdr_id >= 0) ? mesh.GetBdrAttribute(bdr_id) : -1;
162 if (predicate(x, attr)) {
164 output.addElement(tri_id, i, mfem::Geometry::TRIANGLE);
167 output.addElement(quad_id, i, mfem::Geometry::SQUARE);
184 return domain_of_faces(mesh, func);
189 return domain_of_faces(mesh, func);
196 static Domain domain_of_elems(
const mesh_t& mesh, std::function<
bool(std::vector<
tensor<double, d>>,
int)> predicate)
198 assert(mesh.SpaceDimension() == d);
200 Domain output{mesh, mesh.SpaceDimension() , Domain::Type::Elements};
204 mfem::Vector vertices;
205 mesh.GetVertices(vertices);
213 int num_elems = mesh.GetNE();
214 for (
int i = 0; i < num_elems; i++) {
215 mfem::Array<int> vertex_ids;
216 mesh.GetElementVertices(i, vertex_ids);
218 auto x = gather<d>(vertices, vertex_ids);
220 bool add = predicate(x, mesh.GetAttribute(i));
225 output.addElement(tri_id, i, mfem::Geometry::TRIANGLE);
230 if constexpr (d == 2) {
232 output.addElement(quad_id, i, mfem::Geometry::SQUARE);
236 if constexpr (d == 3) {
238 output.addElement(tet_id, i, mfem::Geometry::TETRAHEDRON);
245 output.addElement(hex_id, i, mfem::Geometry::CUBE);
250 SLIC_ERROR(
"unsupported element type");
260 return domain_of_elems<2>(mesh, func);
265 return domain_of_elems<3>(mesh, func);
270 if (element_geometry == mfem::Geometry::SEGMENT) {
271 edge_ids_.push_back(geom_id);
272 mfem_edge_ids_.push_back(elem_id);
273 }
else if (element_geometry == mfem::Geometry::TRIANGLE) {
274 tri_ids_.push_back(geom_id);
275 mfem_tri_ids_.push_back(elem_id);
276 }
else if (element_geometry == mfem::Geometry::SQUARE) {
277 quad_ids_.push_back(geom_id);
278 mfem_quad_ids_.push_back(elem_id);
279 }
else if (element_geometry == mfem::Geometry::TETRAHEDRON) {
280 tet_ids_.push_back(geom_id);
281 mfem_tet_ids_.push_back(elem_id);
282 }
else if (element_geometry == mfem::Geometry::CUBE) {
283 hex_ids_.push_back(geom_id);
284 mfem_hex_ids_.push_back(elem_id);
286 SLIC_ERROR(
"unsupported element type");
291 mfem::Geometry::Type element_geometry)
293 SLIC_ERROR_IF(geom_ids.size() != elem_ids.size(),
294 "To add elements, you must specify a geom_id AND an elem_id for each element");
296 for (std::vector<int>::size_type i = 0; i < geom_ids.size(); ++i) {
297 addElement(geom_ids[i], elem_ids[i], element_geometry);
305 static Domain domain_of_boundary_elems(
const mesh_t& mesh,
308 assert(mesh.SpaceDimension() == d);
310 Domain output{mesh, d - 1, Domain::Type::BoundaryElements};
312 mfem::Array<int> face_id_to_bdr_id = mesh.GetFaceToBdrElMap();
316 mfem::Vector vertices;
317 mesh.GetVertices(vertices);
324 for (
int f = 0; f < mesh.GetNumFaces(); f++) {
326 if (mesh.GetFaceInformation(f).IsInterior())
continue;
328 auto geom = mesh.GetFaceGeometry(f);
330 mfem::Array<int> vertex_ids;
331 mesh.GetFaceVertices(f, vertex_ids);
333 auto x = gather<d>(vertices, vertex_ids);
335 int bdr_id = face_id_to_bdr_id[f];
336 int attr = (bdr_id >= 0) ? mesh.GetBdrAttribute(bdr_id) : -1;
338 bool add = predicate(x, attr);
341 case mfem::Geometry::SEGMENT:
343 output.addElement(edge_id, f, geom);
347 case mfem::Geometry::TRIANGLE:
349 output.addElement(tri_id, f, geom);
353 case mfem::Geometry::SQUARE:
355 output.addElement(quad_id, f, geom);
360 SLIC_ERROR(
"unsupported element type");
370 return domain_of_boundary_elems<2>(mesh, func);
375 return domain_of_boundary_elems<3>(mesh, func);
438 auto par_fes =
dynamic_cast<const mfem::ParFiniteElementSpace*
>(fes);
451 fes->DofsToVDofs(0, local_dof_ids);
453 mfem::Array<int> local_dof_markers;
454 mfem::FiniteElementSpace::ListToMarker(local_dof_ids, par_fes->GetVSize(), local_dof_markers, 1);
456 par_fes->Synchronize(local_dof_markers);
458 mfem::FiniteElementSpace::MarkerToList(local_dof_markers, local_dof_ids);
460 for (
int i = 0; i < local_dof_ids.Size(); i++) {
461 local_dof_ids[i] = par_fes->VDofToDof(local_dof_ids[i]);
468 std::set<int> dof_ids;
469 mfem::Array<int> elem_dofs;
471 std::function<void(
int i, mfem::Array<int>&)> GetDofs;
472 if (
type_ == Type::Elements) {
473 GetDofs = [&](
int i, mfem::Array<int>& vdofs) {
return fes->GetElementDofs(i, vdofs); };
476 if (
type_ == Type::BoundaryElements) {
477 GetDofs = [&](
int i, mfem::Array<int>& vdofs) {
return fes->GetFaceDofs(i, vdofs); };
485 for (
auto elem_id : mfem_edge_ids_) {
486 GetDofs(elem_id, elem_dofs);
487 for (
int i = 0; i < elem_dofs.Size(); i++) {
488 dof_ids.insert(elem_dofs[i]);
494 for (
auto elem_id : mfem_tri_ids_) {
495 GetDofs(elem_id, elem_dofs);
496 for (
int i = 0; i < elem_dofs.Size(); i++) {
497 dof_ids.insert(elem_dofs[i]);
501 for (
auto elem_id : mfem_quad_ids_) {
502 GetDofs(elem_id, elem_dofs);
503 for (
int i = 0; i < elem_dofs.Size(); i++) {
504 dof_ids.insert(elem_dofs[i]);
510 for (
auto elem_id : mfem_tet_ids_) {
511 GetDofs(elem_id, elem_dofs);
512 for (
int i = 0; i < elem_dofs.Size(); i++) {
513 dof_ids.insert(elem_dofs[i]);
517 for (
auto elem_id : mfem_hex_ids_) {
518 GetDofs(elem_id, elem_dofs);
519 for (
int i = 0; i < elem_dofs.Size(); i++) {
520 dof_ids.insert(elem_dofs[i]);
525 mfem::Array<int> uniq_dof_ids(
int(dof_ids.size()));
527 for (
auto id : dof_ids) {
528 uniq_dof_ids[i++] = id;
549 SLIC_ERROR_ROOT_IF(
type_ != Domain::Type::InteriorFaces,
"This method is only for interior face domains");
555 for (
int f : mfem_edge_ids_) {
556 mfem::Mesh::FaceInformation info =
mesh_.GetFaceInformation(f);
558 if (info.IsShared()) {
564 }
else if (
dim_ == 2) {
566 for (
int f : mfem_tri_ids_) {
567 mfem::Mesh::FaceInformation info =
mesh_.GetFaceInformation(f);
569 if (info.IsShared()) {
576 for (
int f : mfem_quad_ids_) {
577 mfem::Mesh::FaceInformation info =
mesh_.GetFaceInformation(f);
579 if (info.IsShared()) {
596 switch (mesh.SpaceDimension()) {
604 SLIC_ERROR(
"In valid spatial dimension. Domains may only be created on 2D or 3D meshes.");
611 switch (mesh.SpaceDimension()) {
619 SLIC_ERROR(
"In valid spatial dimension. Domains may only be created on 2D or 3D meshes.");
627 Domain output{mesh, mesh.SpaceDimension() - 1, Domain::Type::InteriorFaces};
633 for (
int f = 0; f < mesh.GetNumFaces(); f++) {
635 if (!mesh.GetFaceInformation(f).IsInterior())
continue;
637 auto geom = mesh.GetFaceGeometry(f);
640 case mfem::Geometry::SEGMENT:
641 output.edge_ids_.push_back(edge_id++);
642 output.mfem_edge_ids_.push_back(f);
644 case mfem::Geometry::TRIANGLE:
645 output.tri_ids_.push_back(tri_id++);
646 output.mfem_tri_ids_.push_back(f);
648 case mfem::Geometry::SQUARE:
649 output.quad_ids_.push_back(quad_id++);
650 output.mfem_quad_ids_.push_back(f);
653 SLIC_ERROR(
"unsupported element type");
658 output.insert_shared_interior_face_list();
669 using int2 = std::tuple<int, int>;
679 void zip(std::vector<int2>& ab,
const std::vector<int>& a,
const std::vector<int>& b)
682 for (uint32_t i = 0; i < a.size(); i++) {
683 ab[i] = {a[i], b[i]};
688 void unzip(
const std::vector<int2>& ab, std::vector<int>& a, std::vector<int>& b)
692 for (uint32_t i = 0; i < ab.size(); i++) {
694 a[i] = std::get<0>(ab_i);
695 b[i] = std::get<1>(ab_i);
700 template <
typename T>
701 std::vector<T>
set_operation(SET_OPERATION op,
const std::vector<T>& a,
const std::vector<T>& b)
703 using c_iter =
typename std::vector<T>::const_iterator;
704 using b_iter = std::back_insert_iterator<std::vector<T>>;
705 using set_op = std::function<b_iter(c_iter, c_iter, c_iter, c_iter, b_iter)>;
708 if (op == SET_OPERATION::UNION) {
709 combine = std::set_union<c_iter, c_iter, b_iter>;
711 if (op == SET_OPERATION::INTERSECTION) {
712 combine = std::set_intersection<c_iter, c_iter, b_iter>;
714 if (op == SET_OPERATION::DIFFERENCE) {
715 combine = std::set_difference<c_iter, c_iter, b_iter>;
718 std::vector<T> combined;
719 combine(a.begin(), a.end(), b.begin(), b.end(), back_inserter(combined));
732 using Ids = std::vector<int>;
733 auto apply_set_op = [&op](
const Ids& x,
const Ids& y) {
return set_operation(op, x, y); };
735 auto fill_combined_lists = [apply_set_op, &combined](
const Ids& a_ids,
const Ids& a_mfem_ids,
const Ids& b_ids,
736 const Ids& b_mfem_ids, mfem::Geometry::Type g) {
737 auto combined_ids = apply_set_op(a_ids, b_ids);
738 auto combined_mfem_ids = apply_set_op(a_mfem_ids, b_mfem_ids);
739 combined.addElements(combined_ids, combined_mfem_ids, g);
742 if (combined.dim_ == 1) {
743 fill_combined_lists(a.edge_ids_, a.mfem_edge_ids_, b.edge_ids_, b.mfem_edge_ids_, mfem::Geometry::SEGMENT);
746 if (combined.dim_ == 2) {
747 fill_combined_lists(a.tri_ids_, a.mfem_tri_ids_, b.tri_ids_, b.mfem_tri_ids_, mfem::Geometry::TRIANGLE);
748 fill_combined_lists(a.quad_ids_, a.mfem_quad_ids_, b.quad_ids_, b.mfem_quad_ids_, mfem::Geometry::SQUARE);
751 if (combined.dim_ == 3) {
752 fill_combined_lists(a.tet_ids_, a.mfem_tet_ids_, b.tet_ids_, b.mfem_tet_ids_, mfem::Geometry::TETRAHEDRON);
753 fill_combined_lists(a.hex_ids_, a.mfem_hex_ids_, b.hex_ids_, b.mfem_hex_ids_, mfem::Geometry::CUBE);
many of the functions in this file amount to extracting element indices from an mesh_t like
Accelerator functionality.
void zip(std::vector< int2 > &ab, const std::vector< int > &a, const std::vector< int > &b)
combine a pair of arrays of ints into a single array of int2, see also: unzip()
std::vector< T > set_operation(SET_OPERATION op, const std::vector< T > &a, const std::vector< T > &b)
return a std::vector that is the result of applying (a op b)
Domain operator-(const Domain &a, const Domain &b)
create a new domain that is the set difference of a and b
std::vector< tensor< double, d > > gather(const mfem::Vector &coordinates, mfem::Array< int > ids)
gather vertex coordinates for a list of vertices
Domain InteriorFaces(const mesh_t &mesh)
constructs a domain from all the interior face elements in a mesh
Domain operator&(const Domain &a, const Domain &b)
create a new domain that is the intersection of a and b
Domain EntireBoundary(const mesh_t &mesh)
constructs a domain from all the boundary elements in a mesh
Domain operator|(const Domain &a, const Domain &b)
create a new domain that is the union of a and b
void findDomainDofsOnNeighborRanks(const serac::fes_t *fes, mfem::Array< int > &local_dof_ids)
Get local dofs that are part of a domain, but are owned by a neighboring MPI rank.
Domain EntireDomain(const mesh_t &mesh)
constructs a domain from all the elements in a mesh
void unzip(const std::vector< int2 > &ab, std::vector< int > &a, std::vector< int > &b)
split an array of int2 into a pair of arrays of ints, see also: zip()
a generalization of mfem::ElementRestriction that works with multiple kinds of element geometries....
a class for representing a geometric region that can be used for integration
void insert_restriction(const fes_t *fes, FunctionSpace space)
create a restriction operator over this domain, using its FunctionSpace as a key
static Domain ofBoundaryElements(const mesh_t &mesh, std::function< bool(std::vector< vec2 >, int)> func)
create a domain from some subset of the boundary elements (spatial dim == geometry dim + 1) in an mfe...
static Domain ofEdges(const mesh_t &mesh, std::function< bool(std::vector< vec2 >, int)> func)
create a domain from some subset of the edges in an mfem::Mesh
const BlockElementRestriction & get_restriction(FunctionSpace space)
getter for accessing a restriction operator by its function space
std::map< FunctionSpace, BlockElementRestriction > restriction_operators
a collection of restriction operators for the different test/trial spaces appearing in integrals eval...
const mesh_t & mesh_
the underyling mesh for this domain
Type type_
whether the elements in this domain are on the boundary or not
int dim_
the geometric dimension of the domain
void addElement(int geom_id, int elem_id, mfem::Geometry::Type element_geometry)
Add an element to the domain.
mfem::Array< int > dof_list(const fes_t *fes) const
get mfem degree of freedom list for a given FiniteElementSpace
std::vector< int > shared_interior_face_ids_
Ids of interior faces that lie on the boundary shared by two processors.
static Domain ofFaces(const mesh_t &mesh, std::function< bool(std::vector< vec2 >, int)> func)
create a domain from some subset of the faces in an mfem::Mesh
void addElements(const std::vector< int > &geom_id, const std::vector< int > &elem_id, mfem::Geometry::Type element_geometry)
Add a batch of elements to the domain.
void insert_shared_interior_face_list()
Find the list of interior faces shared by two processors to make sure these faces are only integrated...
static Domain ofElements(const mesh_t &mesh, std::function< bool(std::vector< vec2 >, int)> func)
create a domain from some subset of the elements (spatial dim == geometry dim) in an mfem::Mesh
a small POD class for tracking function space metadata
Arbitrary-rank tensor class.