36 #include "smith/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::InteriorBoundaryElements,
550 "This method is only for interior boundary element domains");
556 for (
int f : mfem_edge_ids_) {
557 mfem::Mesh::FaceInformation info =
mesh_.GetFaceInformation(f);
559 if (info.IsShared()) {
565 }
else if (
dim_ == 2) {
567 for (
int f : mfem_tri_ids_) {
568 mfem::Mesh::FaceInformation info =
mesh_.GetFaceInformation(f);
570 if (info.IsShared()) {
577 for (
int f : mfem_quad_ids_) {
578 mfem::Mesh::FaceInformation info =
mesh_.GetFaceInformation(f);
580 if (info.IsShared()) {
597 switch (mesh.SpaceDimension()) {
605 SLIC_ERROR(
"In valid spatial dimension. Domains may only be created on 2D or 3D meshes.");
612 switch (mesh.SpaceDimension()) {
620 SLIC_ERROR(
"In valid spatial dimension. Domains may only be created on 2D or 3D meshes.");
628 Domain output{mesh, mesh.SpaceDimension() - 1, Domain::Type::InteriorBoundaryElements};
634 for (
int f = 0; f < mesh.GetNumFaces(); f++) {
636 if (!mesh.GetFaceInformation(f).IsInterior())
continue;
638 auto geom = mesh.GetFaceGeometry(f);
641 case mfem::Geometry::SEGMENT:
642 output.edge_ids_.push_back(edge_id++);
643 output.mfem_edge_ids_.push_back(f);
645 case mfem::Geometry::TRIANGLE:
646 output.tri_ids_.push_back(tri_id++);
647 output.mfem_tri_ids_.push_back(f);
649 case mfem::Geometry::SQUARE:
650 output.quad_ids_.push_back(quad_id++);
651 output.mfem_quad_ids_.push_back(f);
654 SLIC_ERROR(
"unsupported element type");
659 output.insert_shared_interior_face_list();
669 assert(mesh.SpaceDimension() == d);
670 Domain output{mesh, d - 1, Domain::Type::InteriorBoundaryElements};
672 mfem::Array<int> face_id_to_bdr_id = mesh.GetFaceToBdrElMap();
673 mfem::Vector vertices;
674 mesh.GetVertices(vertices);
680 for (
int f = 0; f < mesh.GetNumFaces(); f++) {
682 if (!mesh.GetFaceInformation(f).IsInterior())
continue;
684 auto geom = mesh.GetFaceGeometry(f);
686 mfem::Array<int> vertex_ids;
687 mesh.GetFaceVertices(f, vertex_ids);
689 auto x = gather<d>(vertices, vertex_ids);
691 int bdr_id = face_id_to_bdr_id[f];
692 int attr = (bdr_id >= 0) ? mesh.GetBdrAttribute(bdr_id) : -1;
694 bool add = predicate(x, attr);
697 case mfem::Geometry::SEGMENT:
699 output.edge_ids_.push_back(edge_id);
700 output.mfem_edge_ids_.push_back(f);
704 case mfem::Geometry::TRIANGLE:
706 output.tri_ids_.push_back(tri_id);
707 output.mfem_tri_ids_.push_back(f);
711 case mfem::Geometry::SQUARE:
713 output.quad_ids_.push_back(quad_id);
714 output.mfem_quad_ids_.push_back(f);
719 SLIC_ERROR(
"unsupported element type");
724 output.insert_shared_interior_face_list();
731 return domain_of_interior_boundaries<2>(mesh, func);
736 return domain_of_interior_boundaries<3>(mesh, func);
745 using int2 = std::tuple<int, int>;
755 void zip(std::vector<int2>& ab,
const std::vector<int>& a,
const std::vector<int>& b)
758 for (uint32_t i = 0; i < a.size(); i++) {
759 ab[i] = {a[i], b[i]};
764 void unzip(
const std::vector<int2>& ab, std::vector<int>& a, std::vector<int>& b)
768 for (uint32_t i = 0; i < ab.size(); i++) {
770 a[i] = std::get<0>(ab_i);
771 b[i] = std::get<1>(ab_i);
776 template <
typename T>
777 std::vector<T>
set_operation(SET_OPERATION op,
const std::vector<T>& a,
const std::vector<T>& b)
779 using c_iter =
typename std::vector<T>::const_iterator;
780 using b_iter = std::back_insert_iterator<std::vector<T>>;
781 using set_op = std::function<b_iter(c_iter, c_iter, c_iter, c_iter, b_iter)>;
784 if (op == SET_OPERATION::UNION) {
785 combine = std::set_union<c_iter, c_iter, b_iter>;
787 if (op == SET_OPERATION::INTERSECTION) {
788 combine = std::set_intersection<c_iter, c_iter, b_iter>;
790 if (op == SET_OPERATION::DIFFERENCE) {
791 combine = std::set_difference<c_iter, c_iter, b_iter>;
794 std::vector<T> combined;
795 combine(a.begin(), a.end(), b.begin(), b.end(), back_inserter(combined));
808 using Ids = std::vector<int>;
809 auto apply_set_op = [&op](
const Ids& x,
const Ids& y) {
return set_operation(op, x, y); };
811 auto fill_combined_lists = [apply_set_op, &combined](
const Ids& a_ids,
const Ids& a_mfem_ids,
const Ids& b_ids,
812 const Ids& b_mfem_ids, mfem::Geometry::Type g) {
813 auto combined_ids = apply_set_op(a_ids, b_ids);
814 auto combined_mfem_ids = apply_set_op(a_mfem_ids, b_mfem_ids);
815 combined.addElements(combined_ids, combined_mfem_ids, g);
818 if (combined.dim_ == 1) {
819 fill_combined_lists(a.edge_ids_, a.mfem_edge_ids_, b.edge_ids_, b.mfem_edge_ids_, mfem::Geometry::SEGMENT);
822 if (combined.dim_ == 2) {
823 fill_combined_lists(a.tri_ids_, a.mfem_tri_ids_, b.tri_ids_, b.mfem_tri_ids_, mfem::Geometry::TRIANGLE);
824 fill_combined_lists(a.quad_ids_, a.mfem_quad_ids_, b.quad_ids_, b.mfem_quad_ids_, mfem::Geometry::SQUARE);
827 if (combined.dim_ == 3) {
828 fill_combined_lists(a.tet_ids_, a.mfem_tet_ids_, b.tet_ids_, b.mfem_tet_ids_, mfem::Geometry::TETRAHEDRON);
829 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.
std::vector< tensor< double, d > > gather(const mfem::Vector &coordinates, mfem::Array< int > ids)
gather vertex coordinates for a list of vertices
Domain EntireInteriorBoundary(const mesh_t &mesh)
constructs a domain from all the interior boundary 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 operator|(const Domain &a, const Domain &b)
create a new domain that is the union of a and b
Domain EntireBoundary(const mesh_t &mesh)
constructs a domain from all the boundary 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()
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)
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()
Domain EntireDomain(const mesh_t &mesh)
constructs a domain from all the elements in a mesh
void findDomainDofsOnNeighborRanks(const smith::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 domain_of_interior_boundaries(const mesh_t &mesh, std::function< bool(std::vector< tensor< double, d >>, int)> predicate)
constructs a domain from some subset of the interior boundary elements in a mesh
mfem::ParFiniteElementSpace & space(FieldState field)
Get the space from the primal field of a field states.
FieldStateWeightedSum operator-(const FieldState &x, const FieldState &y)
subtract two FieldState
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
int dim_
the geometric dimension of the domain
std::vector< int > shared_interior_face_ids_
Ids of interior faces that lie on the boundary shared by two processors.
const BlockElementRestriction & get_restriction(FunctionSpace space)
getter for accessing a restriction operator by its function space
void insert_restriction(const fes_t *fes, FunctionSpace space)
create a restriction operator over this domain, using its FunctionSpace as a key
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
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::map< FunctionSpace, BlockElementRestriction > restriction_operators
a collection of restriction operators for the different test/trial spaces appearing in integrals eval...
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...
Type type_
whether the elements in this domain are on the boundary or not
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.
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
static Domain ofInteriorBoundaryElements(const mesh_t &mesh, std::function< bool(std::vector< vec2 >, int)> func)
create a domain from some subset of the interior boundary elements in an a mesh
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 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 mesh_t & mesh_
the underyling mesh for this domain
a small POD class for tracking function space metadata
Arbitrary-rank tensor class.