Serac  0.1
Serac is an implicit thermal strucural mechanics simulation code.
domain.cpp
1 // Copyright (c) Lawrence Livermore National Security, LLC and
2 // other Serac Project Developers. See the top-level LICENSE file for
3 // details.
4 //
5 // SPDX-License-Identifier: (BSD-3-Clause)
6 
29 
30 #include <cassert>
31 #include <cstdint>
32 #include <cstdlib>
33 #include <iterator>
34 #include <tuple>
35 
36 #include "serac/numerics/functional/element_restriction.hpp"
37 
38 namespace serac {
39 
46 template <int d>
47 std::vector<tensor<double, d>> gather(const mfem::Vector& coordinates, mfem::Array<int> ids)
48 {
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]];
54  }
55  }
56  return x;
57 }
58 
61 
62 template <int d, typename T>
63 static Domain domain_of_edges(const mesh_t& mesh, std::function<T> predicate)
64 {
65  assert(mesh.SpaceDimension() == d);
66 
67  Domain output{mesh, 1 /* edges are 1-dimensional */, Domain::Type::Elements};
68 
69  // layout is undocumented, but it seems to be
70  // [x1, x2, x3, ..., y1, y2, y3 ..., (z1, z2, z3, ...)]
71  mfem::Vector vertices;
72  mesh.GetVertices(vertices);
73 
74  mfem::Array<int> edge_id_to_bdr_id;
75  if (d == 2) {
76  edge_id_to_bdr_id = mesh.GetFaceToBdrElMap();
77  }
78 
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);
83 
84  auto x = gather<d>(vertices, vertex_ids);
85 
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);
91  }
92  } else {
93  if (predicate(x)) {
94  output.addElement(i, i, mfem::Geometry::SEGMENT);
95  }
96  }
97  }
98 
99  return output;
100 }
101 
102 Domain Domain::ofEdges(const mesh_t& mesh, std::function<bool(std::vector<vec2>, int)> func)
103 {
104  return domain_of_edges<2>(mesh, func);
105 }
106 
107 Domain Domain::ofEdges(const mesh_t& mesh, std::function<bool(std::vector<vec3>)> func)
108 {
109  return domain_of_edges<3>(mesh, func);
110 }
111 
114 
115 template <int d>
116 static Domain domain_of_faces(const mesh_t& mesh, std::function<bool(std::vector<tensor<double, d>>, int)> predicate)
117 {
118  assert(mesh.SpaceDimension() == d);
119 
120  Domain output{mesh, 2 /* faces are 2-dimensional */, Domain::Type::Elements};
121 
122  // layout is undocumented, but it seems to be
123  // [x1, x2, x3, ..., y1, y2, y3 ..., (z1, z2, z3, ...)]
124  mfem::Vector vertices;
125  mesh.GetVertices(vertices);
126 
127  mfem::Array<int> face_id_to_bdr_id;
128  if (d == 3) {
129  face_id_to_bdr_id = mesh.GetFaceToBdrElMap();
130  }
131 
132  // faces that satisfy the predicate are added to the domain
133  int num_faces;
134  if (d == 2) {
135  num_faces = mesh.GetNE();
136  } else {
137  num_faces = mesh.GetNumFaces();
138  }
139 
140  int tri_id = 0;
141  int quad_id = 0;
142 
143  for (int i = 0; i < num_faces; i++) {
144  mfem::Array<int> vertex_ids;
145 
146  if (mesh.Dimension() == 2) {
147  mesh.GetElementVertices(i, vertex_ids);
148  } else {
149  mesh.GetFaceVertices(i, vertex_ids);
150  }
151 
152  auto x = gather<d>(vertices, vertex_ids);
153 
154  int attr;
155  if (d == 2) {
156  attr = mesh.GetAttribute(i);
157  } else {
158  int bdr_id = face_id_to_bdr_id[i];
159  attr = (bdr_id >= 0) ? mesh.GetBdrAttribute(bdr_id) : -1;
160  }
161 
162  if (predicate(x, attr)) {
163  if (x.size() == 3) {
164  output.addElement(tri_id, i, mfem::Geometry::TRIANGLE);
165  }
166  if (x.size() == 4) {
167  output.addElement(quad_id, i, mfem::Geometry::SQUARE);
168  }
169  }
170 
171  if (x.size() == 3) {
172  tri_id++;
173  }
174  if (x.size() == 4) {
175  quad_id++;
176  }
177  }
178 
179  return output;
180 }
181 
182 Domain Domain::ofFaces(const mesh_t& mesh, std::function<bool(std::vector<vec2>, int)> func)
183 {
184  return domain_of_faces(mesh, func);
185 }
186 
187 Domain Domain::ofFaces(const mesh_t& mesh, std::function<bool(std::vector<vec3>, int)> func)
188 {
189  return domain_of_faces(mesh, func);
190 }
191 
194 
195 template <int d>
196 static Domain domain_of_elems(const mesh_t& mesh, std::function<bool(std::vector<tensor<double, d>>, int)> predicate)
197 {
198  assert(mesh.SpaceDimension() == d);
199 
200  Domain output{mesh, mesh.SpaceDimension() /* elems can be 2 or 3 dimensional */, Domain::Type::Elements};
201 
202  // layout is undocumented, but it seems to be
203  // [x1, x2, x3, ..., y1, y2, y3 ..., (z1, z2, z3, ...)]
204  mfem::Vector vertices;
205  mesh.GetVertices(vertices);
206 
207  int tri_id = 0;
208  int quad_id = 0;
209  int tet_id = 0;
210  int hex_id = 0;
211 
212  // elements that satisfy the predicate are added to the domain
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);
217 
218  auto x = gather<d>(vertices, vertex_ids);
219 
220  bool add = predicate(x, mesh.GetAttribute(i));
221 
222  switch (x.size()) {
223  case 3:
224  if (add) {
225  output.addElement(tri_id, i, mfem::Geometry::TRIANGLE);
226  }
227  tri_id++;
228  break;
229  case 4:
230  if constexpr (d == 2) {
231  if (add) {
232  output.addElement(quad_id, i, mfem::Geometry::SQUARE);
233  }
234  quad_id++;
235  }
236  if constexpr (d == 3) {
237  if (add) {
238  output.addElement(tet_id, i, mfem::Geometry::TETRAHEDRON);
239  }
240  tet_id++;
241  }
242  break;
243  case 8:
244  if (add) {
245  output.addElement(hex_id, i, mfem::Geometry::CUBE);
246  }
247  hex_id++;
248  break;
249  default:
250  SLIC_ERROR("unsupported element type");
251  break;
252  }
253  }
254 
255  return output;
256 }
257 
258 Domain Domain::ofElements(const mesh_t& mesh, std::function<bool(std::vector<vec2>, int)> func)
259 {
260  return domain_of_elems<2>(mesh, func);
261 }
262 
263 Domain Domain::ofElements(const mesh_t& mesh, std::function<bool(std::vector<vec3>, int)> func)
264 {
265  return domain_of_elems<3>(mesh, func);
266 }
267 
268 void Domain::addElement(int geom_id, int elem_id, mfem::Geometry::Type element_geometry)
269 {
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);
285  } else {
286  SLIC_ERROR("unsupported element type");
287  }
288 }
289 
290 void Domain::addElements(const std::vector<int>& geom_ids, const std::vector<int>& elem_ids,
291  mfem::Geometry::Type element_geometry)
292 {
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");
295 
296  for (std::vector<int>::size_type i = 0; i < geom_ids.size(); ++i) {
297  addElement(geom_ids[i], elem_ids[i], element_geometry);
298  }
299 }
300 
303 
304 template <int d>
305 static Domain domain_of_boundary_elems(const mesh_t& mesh,
306  std::function<bool(std::vector<tensor<double, d>>, int)> predicate)
307 {
308  assert(mesh.SpaceDimension() == d);
309 
310  Domain output{mesh, d - 1, Domain::Type::BoundaryElements};
311 
312  mfem::Array<int> face_id_to_bdr_id = mesh.GetFaceToBdrElMap();
313 
314  // layout is undocumented, but it seems to be
315  // [x1, x2, x3, ..., y1, y2, y3 ..., (z1, z2, z3, ...)]
316  mfem::Vector vertices;
317  mesh.GetVertices(vertices);
318 
319  int edge_id = 0;
320  int tri_id = 0;
321  int quad_id = 0;
322 
323  // faces that satisfy the predicate are added to the domain
324  for (int f = 0; f < mesh.GetNumFaces(); f++) {
325  // discard faces with the wrong type
326  if (mesh.GetFaceInformation(f).IsInterior()) continue;
327 
328  auto geom = mesh.GetFaceGeometry(f);
329 
330  mfem::Array<int> vertex_ids;
331  mesh.GetFaceVertices(f, vertex_ids);
332 
333  auto x = gather<d>(vertices, vertex_ids);
334 
335  int bdr_id = face_id_to_bdr_id[f];
336  int attr = (bdr_id >= 0) ? mesh.GetBdrAttribute(bdr_id) : -1;
337 
338  bool add = predicate(x, attr);
339 
340  switch (geom) {
341  case mfem::Geometry::SEGMENT:
342  if (add) {
343  output.addElement(edge_id, f, geom);
344  }
345  edge_id++;
346  break;
347  case mfem::Geometry::TRIANGLE:
348  if (add) {
349  output.addElement(tri_id, f, geom);
350  }
351  tri_id++;
352  break;
353  case mfem::Geometry::SQUARE:
354  if (add) {
355  output.addElement(quad_id, f, geom);
356  }
357  quad_id++;
358  break;
359  default:
360  SLIC_ERROR("unsupported element type");
361  break;
362  }
363  }
364 
365  return output;
366 }
367 
368 Domain Domain::ofBoundaryElements(const mesh_t& mesh, std::function<bool(std::vector<vec2>, int)> func)
369 {
370  return domain_of_boundary_elems<2>(mesh, func);
371 }
372 
373 Domain Domain::ofBoundaryElements(const mesh_t& mesh, std::function<bool(std::vector<vec3>, int)> func)
374 {
375  return domain_of_boundary_elems<3>(mesh, func);
376 }
377 
436 void findDomainDofsOnNeighborRanks(const serac::fes_t* fes, mfem::Array<int>& local_dof_ids)
437 {
438  auto par_fes = dynamic_cast<const mfem::ParFiniteElementSpace*>(fes);
439  // There's no work to do unless the finite element space really is parallel
440  if (par_fes) {
441  // As far as I can tell, the parallel communication in mfem only works with
442  // vector field dof indexing. So we need to get the parallel-correct scalar
443  // dof ids, we do the following:
444  // (1) transform scalar ldof ids to vector ldof ids,
445  // (2) transform the vector ldof ids into a boolean "marker" ldof field
446  // (3) do our parallel sync, which applies an OR logic operator to the
447  // boolean fields from all ranks at each dof
448  // (4) get the ldof indices of the TRUE values of the parallel-correct
449  // boolean ldof field
450  // (5) transform the parallel-correct vector ldof ids back to scalar dof ids.
451  fes->DofsToVDofs(0, local_dof_ids);
452 
453  mfem::Array<int> local_dof_markers;
454  mfem::FiniteElementSpace::ListToMarker(local_dof_ids, par_fes->GetVSize(), local_dof_markers, 1);
455 
456  par_fes->Synchronize(local_dof_markers);
457 
458  mfem::FiniteElementSpace::MarkerToList(local_dof_markers, local_dof_ids);
459 
460  for (int i = 0; i < local_dof_ids.Size(); i++) {
461  local_dof_ids[i] = par_fes->VDofToDof(local_dof_ids[i]);
462  }
463  }
464 }
465 
466 mfem::Array<int> Domain::dof_list(const serac::fes_t* fes) const
467 {
468  std::set<int> dof_ids;
469  mfem::Array<int> elem_dofs;
470 
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); };
474  }
475 
476  if (type_ == Type::BoundaryElements) {
477  GetDofs = [&](int i, mfem::Array<int>& vdofs) { return fes->GetFaceDofs(i, vdofs); };
478  }
479 
480  if (dim_ == 0) {
481  // sam: what to do with vertex sets?
482  }
483 
484  if (dim_ == 1) {
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]);
489  }
490  }
491  }
492 
493  if (dim_ == 2) {
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]);
498  }
499  }
500 
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]);
505  }
506  }
507  }
508 
509  if (dim_ == 3) {
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]);
514  }
515  }
516 
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]);
521  }
522  }
523  }
524 
525  mfem::Array<int> uniq_dof_ids(int(dof_ids.size()));
526  int i = 0;
527  for (auto id : dof_ids) {
528  uniq_dof_ids[i++] = id;
529  }
530 
531  findDomainDofsOnNeighborRanks(fes, uniq_dof_ids);
532 
533  return uniq_dof_ids;
534 }
535 
536 void Domain::insert_restriction(const serac::fes_t* fes, FunctionSpace space)
537 {
538  // if we don't already have a BlockElementRestriction for this FunctionSpace, make one
539  if (restriction_operators.count(space) == 0) {
540  restriction_operators[space] = BlockElementRestriction(fes, *this);
541  }
542 }
543 
545 
547 {
548  // Weights only need to be computed for Domain of InteriorFaces type
549  SLIC_ERROR_ROOT_IF(type_ != Domain::Type::InteriorFaces, "This method is only for interior face domains");
550 
551  // make a list if we don't already have one
552  if (shared_interior_face_ids_.empty()) {
553  if (dim_ == 1) {
554  int i = 0;
555  for (int f : mfem_edge_ids_) {
556  mfem::Mesh::FaceInformation info = mesh_.GetFaceInformation(f);
557 
558  if (info.IsShared()) {
559  shared_interior_face_ids_.push_back(i);
560  }
561 
562  ++i;
563  }
564  } else if (dim_ == 2) {
565  int i = 0;
566  for (int f : mfem_tri_ids_) {
567  mfem::Mesh::FaceInformation info = mesh_.GetFaceInformation(f);
568 
569  if (info.IsShared()) {
570  shared_interior_face_ids_.push_back(i);
571  }
572 
573  ++i;
574  }
575 
576  for (int f : mfem_quad_ids_) {
577  mfem::Mesh::FaceInformation info = mesh_.GetFaceInformation(f);
578 
579  if (info.IsShared()) {
580  shared_interior_face_ids_.push_back(i);
581  }
582 
583  ++i;
584  }
585  }
586  }
587 }
588 
593 
594 Domain EntireDomain(const mesh_t& mesh)
595 {
596  switch (mesh.SpaceDimension()) {
597  case 2:
598  return Domain::ofElements(mesh, [](std::vector<vec2>, int) { return true; });
599  break;
600  case 3:
601  return Domain::ofElements(mesh, [](std::vector<vec3>, int) { return true; });
602  break;
603  default:
604  SLIC_ERROR("In valid spatial dimension. Domains may only be created on 2D or 3D meshes.");
605  exit(-1);
606  }
607 }
608 
609 Domain EntireBoundary(const mesh_t& mesh)
610 {
611  switch (mesh.SpaceDimension()) {
612  case 2:
613  return Domain::ofBoundaryElements(mesh, [](std::vector<vec2>, int) { return true; });
614  break;
615  case 3:
616  return Domain::ofBoundaryElements(mesh, [](std::vector<vec3>, int) { return true; });
617  break;
618  default:
619  SLIC_ERROR("In valid spatial dimension. Domains may only be created on 2D or 3D meshes.");
620  exit(-1);
621  }
622 }
623 
625 Domain InteriorFaces(const mesh_t& mesh)
626 {
627  Domain output{mesh, mesh.SpaceDimension() - 1, Domain::Type::InteriorFaces};
628 
629  int edge_id = 0;
630  int tri_id = 0;
631  int quad_id = 0;
632 
633  for (int f = 0; f < mesh.GetNumFaces(); f++) {
634  // discard faces with the wrong type
635  if (!mesh.GetFaceInformation(f).IsInterior()) continue;
636 
637  auto geom = mesh.GetFaceGeometry(f);
638 
639  switch (geom) {
640  case mfem::Geometry::SEGMENT:
641  output.edge_ids_.push_back(edge_id++);
642  output.mfem_edge_ids_.push_back(f);
643  break;
644  case mfem::Geometry::TRIANGLE:
645  output.tri_ids_.push_back(tri_id++);
646  output.mfem_tri_ids_.push_back(f);
647  break;
648  case mfem::Geometry::SQUARE:
649  output.quad_ids_.push_back(quad_id++);
650  output.mfem_quad_ids_.push_back(f);
651  break;
652  default:
653  SLIC_ERROR("unsupported element type");
654  break;
655  }
656  }
657 
658  output.insert_shared_interior_face_list();
659 
660  return output;
661 }
662 
667 
669 using int2 = std::tuple<int, int>;
670 enum SET_OPERATION
671 {
672  UNION,
673  INTERSECTION,
674  DIFFERENCE
675 };
677 
679 void zip(std::vector<int2>& ab, const std::vector<int>& a, const std::vector<int>& b)
680 {
681  ab.resize(a.size());
682  for (uint32_t i = 0; i < a.size(); i++) {
683  ab[i] = {a[i], b[i]};
684  }
685 }
686 
688 void unzip(const std::vector<int2>& ab, std::vector<int>& a, std::vector<int>& b)
689 {
690  a.resize(ab.size());
691  b.resize(ab.size());
692  for (uint32_t i = 0; i < ab.size(); i++) {
693  auto ab_i = ab[i];
694  a[i] = std::get<0>(ab_i);
695  b[i] = std::get<1>(ab_i);
696  }
697 }
698 
700 template <typename T>
701 std::vector<T> set_operation(SET_OPERATION op, const std::vector<T>& a, const std::vector<T>& b)
702 {
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)>;
706 
707  set_op combine;
708  if (op == SET_OPERATION::UNION) {
709  combine = std::set_union<c_iter, c_iter, b_iter>;
710  }
711  if (op == SET_OPERATION::INTERSECTION) {
712  combine = std::set_intersection<c_iter, c_iter, b_iter>;
713  }
714  if (op == SET_OPERATION::DIFFERENCE) {
715  combine = std::set_difference<c_iter, c_iter, b_iter>;
716  }
717 
718  std::vector<T> combined;
719  combine(a.begin(), a.end(), b.begin(), b.end(), back_inserter(combined));
720  return combined;
721 }
722 
724 Domain set_operation(SET_OPERATION op, const Domain& a, const Domain& b)
725 {
726  assert(&a.mesh_ == &b.mesh_);
727  assert(a.dim_ == b.dim_);
728  assert(a.type_ == b.type_);
729 
730  Domain combined{a.mesh_, a.dim_, a.type_};
731 
732  using Ids = std::vector<int>;
733  auto apply_set_op = [&op](const Ids& x, const Ids& y) { return set_operation(op, x, y); };
734 
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);
740  };
741 
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);
744  }
745 
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);
749  }
750 
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);
754  }
755 
756  return combined;
757 }
758 
759 Domain operator|(const Domain& a, const Domain& b) { return set_operation(SET_OPERATION::UNION, a, b); }
760 Domain operator&(const Domain& a, const Domain& b) { return set_operation(SET_OPERATION::INTERSECTION, a, b); }
761 Domain operator-(const Domain& a, const Domain& b) { return set_operation(SET_OPERATION::DIFFERENCE, a, b); }
762 
763 } // namespace serac
many of the functions in this file amount to extracting element indices from an mesh_t like
Accelerator functionality.
Definition: serac.cpp:36
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()
Definition: domain.cpp:679
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)
Definition: domain.cpp:701
Domain operator-(const Domain &a, const Domain &b)
create a new domain that is the set difference of a and b
Definition: domain.cpp:761
std::vector< tensor< double, d > > gather(const mfem::Vector &coordinates, mfem::Array< int > ids)
gather vertex coordinates for a list of vertices
Definition: domain.cpp:47
Domain InteriorFaces(const mesh_t &mesh)
constructs a domain from all the interior face elements in a mesh
Definition: domain.cpp:625
Domain operator&(const Domain &a, const Domain &b)
create a new domain that is the intersection of a and b
Definition: domain.cpp:760
Domain EntireBoundary(const mesh_t &mesh)
constructs a domain from all the boundary elements in a mesh
Definition: domain.cpp:609
Domain operator|(const Domain &a, const Domain &b)
create a new domain that is the union of a and b
Definition: domain.cpp:759
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.
Definition: domain.cpp:436
Domain EntireDomain(const mesh_t &mesh)
constructs a domain from all the elements in a mesh
Definition: domain.cpp:594
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()
Definition: domain.cpp:688
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
Definition: domain.hpp:33
void insert_restriction(const fes_t *fes, FunctionSpace space)
create a restriction operator over this domain, using its FunctionSpace as a key
Definition: domain.cpp:536
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...
Definition: domain.cpp:368
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
Definition: domain.cpp:102
const BlockElementRestriction & get_restriction(FunctionSpace space)
getter for accessing a restriction operator by its function space
Definition: domain.cpp:544
std::map< FunctionSpace, BlockElementRestriction > restriction_operators
a collection of restriction operators for the different test/trial spaces appearing in integrals eval...
Definition: domain.hpp:103
const mesh_t & mesh_
the underyling mesh for this domain
Definition: domain.hpp:45
Type type_
whether the elements in this domain are on the boundary or not
Definition: domain.hpp:51
int dim_
the geometric dimension of the domain
Definition: domain.hpp:48
void addElement(int geom_id, int elem_id, mfem::Geometry::Type element_geometry)
Add an element to the domain.
Definition: domain.cpp:268
mfem::Array< int > dof_list(const fes_t *fes) const
get mfem degree of freedom list for a given FiniteElementSpace
Definition: domain.cpp:466
std::vector< int > shared_interior_face_ids_
Ids of interior faces that lie on the boundary shared by two processors.
Definition: domain.hpp:106
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
Definition: domain.cpp:182
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.
Definition: domain.cpp:290
void insert_shared_interior_face_list()
Find the list of interior faces shared by two processors to make sure these faces are only integrated...
Definition: domain.cpp:546
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
Definition: domain.cpp:258
a small POD class for tracking function space metadata
Arbitrary-rank tensor class.
Definition: tensor.hpp:28