MFEM  v4.5.2
Finite element discretization library
psubmesh.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2023, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 
12 #include "../../config/config.hpp"
13 
14 #ifdef MFEM_USE_MPI
15 
16 #include <iostream>
17 #include <unordered_set>
18 #include <algorithm>
19 #include "psubmesh.hpp"
20 #include "submesh_utils.hpp"
21 #include "../segment.hpp"
22 
23 namespace mfem
24 {
25 
27  Array<int> &domain_attributes)
28 {
29  return ParSubMesh(parent, SubMesh::From::Domain, domain_attributes);
30 }
31 
33  Array<int> &boundary_attributes)
34 {
35  return ParSubMesh(parent, SubMesh::From::Boundary, boundary_attributes);
36 }
37 
38 ParSubMesh::ParSubMesh(const ParMesh &parent, SubMesh::From from,
39  Array<int> &attributes) : parent_(parent), from_(from), attributes_(attributes)
40 {
41  if (Nonconforming())
42  {
43  MFEM_ABORT("SubMesh does not support non-conforming meshes");
44  }
45 
46  MyComm = parent.GetComm();
47  NRanks = parent.GetNRanks();
48  MyRank = parent.GetMyRank();
49 
50  if (from == SubMesh::From::Domain)
51  {
52  InitMesh(parent.Dimension(), parent.SpaceDimension(), 0, 0, 0);
53 
54  std::tie(parent_vertex_ids_,
55  parent_element_ids_) = SubMeshUtils::AddElementsToMesh(parent_, *this,
56  attributes_);
57  }
58  else if (from == SubMesh::From::Boundary)
59  {
60  InitMesh(parent.Dimension() - 1, parent.SpaceDimension(), 0, 0, 0);
61 
62  std::tie(parent_vertex_ids_,
63  parent_element_ids_) = SubMeshUtils::AddElementsToMesh(parent_, *this,
64  attributes_, true);
65  }
66 
67  // Don't let boundary elements get generated automatically. This would
68  // generate boundary elements on each rank locally, which is topologically
69  // wrong for the distributed SubMesh.
70  FinalizeTopology(false);
71 
72  parent_to_submesh_vertex_ids_.SetSize(parent_.GetNV());
73  parent_to_submesh_vertex_ids_ = -1;
74  for (int i = 0; i < parent_vertex_ids_.Size(); i++)
75  {
76  parent_to_submesh_vertex_ids_[parent_vertex_ids_[i]] = i;
77  }
78 
79  DSTable v2v(parent_.GetNV());
80  parent_.GetVertexToVertexTable(v2v);
81  for (int i = 0; i < NumOfEdges; i++)
82  {
83  Array<int> lv;
84  GetEdgeVertices(i, lv);
85 
86  // Find vertices/edge in parent mesh
87  int parent_edge_id = v2v(parent_vertex_ids_[lv[0]], parent_vertex_ids_[lv[1]]);
88  parent_edge_ids_.Append(parent_edge_id);
89  }
90 
91  parent_to_submesh_edge_ids_.SetSize(parent.GetNEdges());
92  parent_to_submesh_edge_ids_ = -1;
93  for (int i = 0; i < parent_edge_ids_.Size(); i++)
94  {
95  parent_to_submesh_edge_ids_[parent_edge_ids_[i]] = i;
96  }
97 
98  if (Dim == 3)
99  {
100  parent_face_ids_ = SubMeshUtils::BuildFaceMap(parent_, *this,
101  parent_element_ids_);
102 
103  parent_to_submesh_face_ids_.SetSize(parent.GetNFaces());
104  parent_to_submesh_face_ids_ = -1;
105  for (int i = 0; i < parent_face_ids_.Size(); i++)
106  {
107  parent_to_submesh_face_ids_[parent_face_ids_[i]] = i;
108  }
109  }
110 
111  ListOfIntegerSets groups;
112  IntegerSet group;
113  // the first group is the local one
114  group.Recreate(1, &MyRank);
115  groups.Insert(group);
116 
117  // Every rank containing elements of the ParSubMesh attributes now has a
118  // local ParSubMesh. We have to connect the local meshes and assign global
119  // boundaries correctly.
120 
121  Array<int> rhvtx;
122  FindSharedVerticesRanks(rhvtx);
123  AppendSharedVerticesGroups(groups, rhvtx);
124 
125  Array<int> rhe;
126  FindSharedEdgesRanks(rhe);
127  AppendSharedEdgesGroups(groups, rhe);
128 
129  Array<int> rhq, rht;
130  if (Dim == 3)
131  {
132  FindSharedFacesRanks(rht, rhq);
133  AppendSharedFacesGroups(groups, rht, rhq);
134  }
135 
136  // Build the group communication topology
138  gtopo.Create(groups, 822);
139  int ngroups = groups.Size()-1;
140 
141  int nsverts, nsedges, nstrias, nsquads;
142  BuildVertexGroup(ngroups, rhvtx, nsverts);
143  BuildEdgeGroup(ngroups, rhe, nsedges);
144  if (Dim == 3)
145  {
146  BuildFaceGroup(ngroups, rht, nstrias, rhq, nsquads);
147  }
148  else
149  {
150  group_stria.MakeI(ngroups);
151  group_stria.MakeJ();
153 
154  group_squad.MakeI(ngroups);
155  group_squad.MakeJ();
157  }
158 
159  BuildSharedVerticesMapping(nsverts, rhvtx);
160  BuildSharedEdgesMapping(nsedges, rhe);
161  if (Dim == 3)
162  {
163  BuildSharedFacesMapping(nstrias, rht, nsquads, rhq);
164  }
165 
167 
168  // Add boundaries
169  {
170  int num_of_faces_or_edges = (Dim == 2) ? NumOfEdges : NumOfFaces;
171  Array<int> &be2face = (Dim == 2) ? be_to_edge : be_to_face;
172 
173  if (Dim == 3)
174  {
175  // In 3D we check for `bel_to_edge`. It shouldn't have been set
176  // previously.
177  delete bel_to_edge;
178  bel_to_edge = nullptr;
179  }
180 
181  NumOfBdrElements = 0;
182  for (int i = 0; i < num_of_faces_or_edges; i++)
183  {
185  {
187  }
188  }
189 
190  boundary.SetSize(NumOfBdrElements);
191  be2face.SetSize(NumOfBdrElements);
192  Array<int> parent_face_to_be;
193  if (Dim == 3)
194  {
195  parent_face_to_be = parent.GetFaceToBdrElMap();
196  }
197  for (int i = 0, j = 0; i < num_of_faces_or_edges; i++)
198  {
199  if (GetFaceInformation(i).IsBoundary())
200  {
201  boundary[j] = faces[i]->Duplicate(this);
202 
203  if (Dim == 3)
204  {
205  int pbeid = parent_face_to_be[parent_face_ids_[i]];
206  if (pbeid != -1)
207  {
208  boundary[j]->SetAttribute(parent.GetBdrAttribute(pbeid));
209  }
210  else
211  {
212  boundary[j]->SetAttribute(SubMesh::GENERATED_ATTRIBUTE);
213  }
214  }
215  else
216  {
217  boundary[j]->SetAttribute(SubMesh::GENERATED_ATTRIBUTE);
218  }
219  be2face[j++] = i;
220  }
221  }
222  }
223 
224  if (Dim == 3)
225  {
227  }
228 
229  // If the parent ParMesh has nodes and therefore is defined on a higher order
230  // geometry, we define this ParSubMesh as a curved ParSubMesh and transfer
231  // the GridFunction from the parent ParMesh to the ParSubMesh.
232  const GridFunction *parent_nodes = parent_.GetNodes();
233  if (parent_nodes)
234  {
235  const FiniteElementSpace *parent_fes = parent_nodes->FESpace();
236 
237  SetCurvature(
238  parent_fes->FEColl()->GetOrder(),
239  parent_fes->IsDGSpace(),
240  spaceDim,
241  parent_fes->GetOrdering());
242 
243  const ParGridFunction* pn = dynamic_cast<const ParGridFunction*>
244  (parent_.GetNodes());
245  MFEM_ASSERT(pn,
246  "Internal error. Object is supposed to be ParGridFunction.");
247 
248  ParGridFunction* n = dynamic_cast<ParGridFunction*>
249  (this->GetNodes());
250  MFEM_ASSERT(n,
251  "Internal error. Object is supposed to be ParGridFunction.");
252 
253  Transfer(*pn, *n);
254  }
255 
256  if (Dim > 1)
257  {
258  el_to_edge = new Table;
260  }
261 
262  SetAttributes();
263  Finalize();
264 }
265 
266 void ParSubMesh::FindSharedVerticesRanks(Array<int> &rhvtx)
267 {
268  // create a GroupCommunicator on the shared vertices
269  GroupCommunicator svert_comm(parent_.gtopo);
270  parent_.GetSharedVertexCommunicator(svert_comm);
271  // Number of shared vertices
272  int nsvtx = svert_comm.GroupLDofTable().Size_of_connections();
273 
274  rhvtx.SetSize(nsvtx);
275  rhvtx = 0;
276 
277  // On each rank of the group, locally determine if the shared vertex is in
278  // the SubMesh.
279  for (int g = 1, sv = 0; g < parent_.GetNGroups(); g++)
280  {
281  const int group_sz = parent_.gtopo.GetGroupSize(g);
282  MFEM_VERIFY((unsigned int)group_sz <= 8*sizeof(int), // 32
283  "Group size too large. Groups with more than 32 ranks are not supported, yet.");
284  const int* group_lproc = parent_.gtopo.GetGroup(g);
285 
286  const int* my_group_id_ptr = std::find(group_lproc, group_lproc+group_sz, 0);
287  MFEM_ASSERT(my_group_id_ptr != group_lproc+group_sz, "internal error");
288 
289  const int my_group_id = my_group_id_ptr-group_lproc;
290 
291  for (int gv = 0; gv < parent_.GroupNVertices(g); gv++, sv++)
292  {
293  int plvtx = parent_.GroupVertex(g, gv);
294  int submesh_vertex_id = parent_to_submesh_vertex_ids_[plvtx];
295  if (submesh_vertex_id != -1)
296  {
297  rhvtx[sv] |= 1 << my_group_id;
298  }
299  }
300  }
301 
302  // Compute the sum on the root rank and broadcast the result to all ranks.
303  svert_comm.Reduce(rhvtx, GroupCommunicator::Sum);
304  svert_comm.Bcast<int>(rhvtx, 0);
305 }
306 
307 void ParSubMesh::FindSharedEdgesRanks(Array<int> &rhe)
308 {
309  // create a GroupCommunicator on the shared edges
310  GroupCommunicator sedge_comm(parent_.gtopo);
311  parent_.GetSharedEdgeCommunicator(sedge_comm);
312 
313  int nsedges = sedge_comm.GroupLDofTable().Size_of_connections();
314 
315  // see rhvtx description
316  rhe.SetSize(nsedges);
317  rhe = 0;
318 
319  // On each rank of the group, locally determine if the shared edge is in
320  // the SubMesh.
321  for (int g = 1, se = 0; g < parent_.GetNGroups(); g++)
322  {
323  const int group_sz = parent_.gtopo.GetGroupSize(g);
324  MFEM_VERIFY((unsigned int)group_sz <= 8*sizeof(int), // 32
325  "Group size too large. Groups with more than 32 ranks are not supported, yet.");
326  const int* group_lproc = parent_.gtopo.GetGroup(g);
327 
328  const int* my_group_id_ptr = std::find(group_lproc, group_lproc+group_sz, 0);
329  MFEM_ASSERT(my_group_id_ptr != group_lproc+group_sz, "internal error");
330 
331  // rank id inside this group
332  const int my_group_id = my_group_id_ptr-group_lproc;
333 
334  for (int ge = 0; ge < parent_.GroupNEdges(g); ge++, se++)
335  {
336  int ple, o;
337  parent_.GroupEdge(g, ge, ple, o);
338  int submesh_edge_id = parent_to_submesh_edge_ids_[ple];
339  if (submesh_edge_id != -1)
340  {
341  rhe[se] |= 1 << my_group_id;
342  }
343  }
344  }
345 
346  // Compute the sum on the root rank and broadcast the result to all ranks.
347  sedge_comm.Reduce(rhe, GroupCommunicator::Sum);
348  sedge_comm.Bcast<int>(rhe, 0);
349 }
350 
351 void ParSubMesh::FindSharedFacesRanks(Array<int>& rht, Array<int> &rhq)
352 {
353  GroupCommunicator squad_comm(parent_.gtopo);
354  parent_.GetSharedQuadCommunicator(squad_comm);
355 
356  int nsquad = squad_comm.GroupLDofTable().Size_of_connections();
357 
358  rhq.SetSize(nsquad);
359  rhq = 0;
360 
361  for (int g = 1, sq = 0; g < parent_.GetNGroups(); g++)
362  {
363  for (int gq = 0; gq < parent_.GroupNQuadrilaterals(g); gq++, sq++)
364  {
365  // Group size of a shared face is always 2
366 
367  int plq, o;
368  parent_.GroupQuadrilateral(g, gq, plq, o);
369  int submesh_face_id = parent_to_submesh_face_ids_[plq];
370  if (submesh_face_id != -1)
371  {
372  rhq[sq] = 1;
373  }
374  }
375  }
376 
377  // Compute the sum on the root rank and broadcast the result to all ranks.
378  squad_comm.Reduce(rhq, GroupCommunicator::Sum);
379  squad_comm.Bcast<int>(rhq, 0);
380 
381  GroupCommunicator stria_comm(parent_.gtopo);
382  parent_.GetSharedTriCommunicator(stria_comm);
383 
384  int nstria = stria_comm.GroupLDofTable().Size_of_connections();
385 
386  rht.SetSize(nstria);
387  rht = 0;
388 
389  for (int g = 1, st = 0; g < parent_.GetNGroups(); g++)
390  {
391  for (int gt = 0; gt < parent_.GroupNTriangles(g); gt++, st++)
392  {
393  // Group size of a shared face is always 2
394 
395  int plt, o;
396  parent_.GroupTriangle(g, gt, plt, o);
397  int submesh_face_id = parent_to_submesh_face_ids_[plt];
398  if (submesh_face_id != -1)
399  {
400  rht[st] = 1;
401  }
402  }
403  }
404 
405  // Compute the sum on the root rank and broadcast the result to all ranks.
406  stria_comm.Reduce(rht, GroupCommunicator::Sum);
407  stria_comm.Bcast<int>(rht, 0);
408 }
409 
410 
411 void ParSubMesh::AppendSharedVerticesGroups(ListOfIntegerSets &groups,
412  Array<int> &rhvtx)
413 {
414  IntegerSet group;
415 
416  for (int g = 1, sv = 0; g < parent_.GetNGroups(); g++)
417  {
418  const int group_sz = parent_.gtopo.GetGroupSize(g);
419  MFEM_VERIFY((unsigned int)group_sz <= 8*sizeof(int), // 32
420  "Group size too large. Groups with more than 32 ranks are not supported, yet.");
421  const int* group_lproc = parent_.gtopo.GetGroup(g);
422 
423  const int* my_group_id_ptr = std::find(group_lproc, group_lproc+group_sz, 0);
424  MFEM_ASSERT(my_group_id_ptr != group_lproc+group_sz, "internal error");
425 
426  const int my_group_id = my_group_id_ptr-group_lproc;
427 
428  for (int gv = 0; gv < parent_.GroupNVertices(g); gv++, sv++)
429  {
430  // Returns the parents local vertex id
431  int plvtx = parent_.GroupVertex(g, gv);
432  int submesh_vtx = parent_to_submesh_vertex_ids_[plvtx];
433 
434  // Reusing the `rhvtx` array as shared vertex to group array.
435  if (submesh_vtx == -1)
436  {
437  // parent shared vertex is not in SubMesh
438  rhvtx[sv] = -1;
439  }
440  else if (rhvtx[sv] & ~(1 << my_group_id))
441  {
442  // shared vertex is present on this rank and others
443  MFEM_ASSERT(rhvtx[sv] & (1 << my_group_id), "error again");
444 
445  // determine which other ranks have the shared vertex
446  Array<int> &ranks = group;
447  ranks.SetSize(0);
448  for (int i = 0; i < group_sz; i++)
449  {
450  if ((rhvtx[sv] >> i) & 1)
451  {
452  ranks.Append(parent_.gtopo.GetNeighborRank(group_lproc[i]));
453  }
454  }
455  MFEM_ASSERT(ranks.Size() >= 2, "internal error");
456 
457  rhvtx[sv] = groups.Insert(group) - 1;
458  }
459  else
460  {
461  // previously shared vertex is only present on this rank
462  rhvtx[sv] = -1;
463  }
464  }
465  }
466 }
467 
468 void ParSubMesh::AppendSharedEdgesGroups(ListOfIntegerSets &groups,
469  Array<int> &rhe)
470 {
471  IntegerSet group;
472 
473  for (int g = 1, se = 0; g < parent_.GetNGroups(); g++)
474  {
475  const int group_sz = parent_.gtopo.GetGroupSize(g);
476  MFEM_VERIFY((unsigned int)group_sz <= 8*sizeof(int), // 32
477  "Group size too large. Groups with more than 32 ranks are not supported, yet.");
478  const int* group_lproc = parent_.gtopo.GetGroup(g);
479 
480  const int* my_group_id_ptr = std::find(group_lproc, group_lproc+group_sz, 0);
481  MFEM_ASSERT(my_group_id_ptr != group_lproc+group_sz, "internal error");
482 
483  const int my_group_id = my_group_id_ptr-group_lproc;
484 
485  for (int ge = 0; ge < parent_.GroupNEdges(g); ge++, se++)
486  {
487  int ple, o;
488  parent_.GroupEdge(g, ge, ple, o);
489  int submesh_edge = parent_to_submesh_edge_ids_[ple];
490 
491  // Reusing the `rhe` array as shared edge to group array.
492  if (submesh_edge == -1)
493  {
494  // parent shared edge is not in SubMesh
495  rhe[se] = -1;
496  }
497  else if (rhe[se] & ~(1 << my_group_id))
498  {
499  // shared edge is present on this rank and others
500 
501  // determine which other ranks have the shared edge
502  Array<int> &ranks = group;
503  ranks.SetSize(0);
504  for (int i = 0; i < group_sz; i++)
505  {
506  if ((rhe[se] >> i) & 1)
507  {
508  ranks.Append(parent_.gtopo.GetNeighborRank(group_lproc[i]));
509  }
510  }
511  MFEM_ASSERT(ranks.Size() >= 2, "internal error");
512 
513  rhe[se] = groups.Insert(group) - 1;
514  }
515  else
516  {
517  // previously shared edge is only present on this rank
518  rhe[se] = -1;
519  }
520  }
521  }
522 }
523 
524 void ParSubMesh::AppendSharedFacesGroups(ListOfIntegerSets &groups,
525  Array<int>& rht, Array<int> &rhq)
526 {
527  IntegerSet quad_group;
528 
529  for (int g = 1, sq = 0; g < parent_.GetNGroups(); g++)
530  {
531  const int* group_lproc = parent_.gtopo.GetGroup(g);
532  for (int gq = 0; gq < parent_.GroupNQuadrilaterals(g); gq++, sq++)
533  {
534  const int group_sz = parent_.gtopo.GetGroupSize(g);
535  MFEM_ASSERT(group_sz == 2, "internal error");
536 
537  int plq, o;
538  parent_.GroupQuadrilateral(g, gq, plq, o);
539  int submesh_face_id = parent_to_submesh_face_ids_[plq];
540 
541  // Reusing the `rhq` array as shared face to group array.
542  if (submesh_face_id == -1)
543  {
544  // parent shared face is not in SubMesh
545  rhq[sq] = -1;
546  }
547  else if (rhq[sq] == group_sz)
548  {
549  // shared face is present on this rank and others
550 
551  // There can only be two ranks in this group sharing faces. Add
552  // all ranks to a new communication group.
553  Array<int> &ranks = quad_group;
554  ranks.SetSize(0);
555  ranks.Append(parent_.gtopo.GetNeighborRank(group_lproc[0]));
556  ranks.Append(parent_.gtopo.GetNeighborRank(group_lproc[1]));
557 
558  rhq[sq] = groups.Insert(quad_group) - 1;
559  }
560  else
561  {
562  // previously shared edge is only present on this rank
563  rhq[sq] = -1;
564  }
565  }
566  }
567 
568  IntegerSet tria_group;
569 
570  for (int g = 1, st = 0; g < parent_.GetNGroups(); g++)
571  {
572  const int* group_lproc = parent_.gtopo.GetGroup(g);
573  for (int gt = 0; gt < parent_.GroupNTriangles(g); gt++, st++)
574  {
575  const int group_sz = parent_.gtopo.GetGroupSize(g);
576  MFEM_ASSERT(group_sz == 2, "internal error");
577 
578  int plt, o;
579  parent_.GroupTriangle(g, gt, plt, o);
580  int submesh_face_id = parent_to_submesh_face_ids_[plt];
581 
582  // Reusing the `rht` array as shared face to group array.
583  if (submesh_face_id == -1)
584  {
585  // parent shared face is not in SubMesh
586  rht[st] = -1;
587  }
588  else if (rht[st] == group_sz)
589  {
590  // shared face is present on this rank and others
591 
592  // There can only be two ranks in this group sharing faces. Add
593  // all ranks to a new communication group.
594  Array<int> &ranks = tria_group;
595  ranks.SetSize(0);
596  ranks.Append(parent_.gtopo.GetNeighborRank(group_lproc[0]));
597  ranks.Append(parent_.gtopo.GetNeighborRank(group_lproc[1]));
598 
599  rht[st] = groups.Insert(tria_group) - 1;
600  }
601  else
602  {
603  // previously shared edge is only present on this rank
604  rht[st] = -1;
605  }
606  }
607  }
608 }
609 
610 void ParSubMesh::BuildVertexGroup(int ngroups, const Array<int>& rhvtx,
611  int& nsverts)
612 {
613  group_svert.MakeI(ngroups);
614  for (int i = 0; i < rhvtx.Size(); i++)
615  {
616  if (rhvtx[i] >= 0)
617  {
618  group_svert.AddAColumnInRow(rhvtx[i]);
619  }
620  }
621 
622  group_svert.MakeJ();
623  nsverts = 0;
624  for (int i = 0; i < rhvtx.Size(); i++)
625  {
626  if (rhvtx[i] >= 0)
627  {
628  group_svert.AddConnection(rhvtx[i], nsverts++);
629  }
630  }
632 }
633 
634 void ParSubMesh::BuildEdgeGroup(int ngroups, const Array<int>& rhe,
635  int& nsedges)
636 {
637  group_sedge.MakeI(ngroups);
638  for (int i = 0; i < rhe.Size(); i++)
639  {
640  if (rhe[i] >= 0)
641  {
643  }
644  }
645 
646  group_sedge.MakeJ();
647  nsedges = 0;
648  for (int i = 0; i < rhe.Size(); i++)
649  {
650  if (rhe[i] >= 0)
651  {
652  group_sedge.AddConnection(rhe[i], nsedges++);
653  }
654  }
656 }
657 
658 void ParSubMesh::BuildFaceGroup(int ngroups, const Array<int>& rht,
659  int& nstrias, const Array<int>& rhq, int& nsquads)
660 {
661  group_squad.MakeI(ngroups);
662  for (int i = 0; i < rhq.Size(); i++)
663  {
664  if (rhq[i] >= 0)
665  {
667  }
668  }
669 
670  group_squad.MakeJ();
671  nsquads = 0;
672  for (int i = 0; i < rhq.Size(); i++)
673  {
674  if (rhq[i] >= 0)
675  {
676  group_squad.AddConnection(rhq[i], nsquads++);
677  }
678  }
680 
681  group_stria.MakeI(ngroups);
682  for (int i = 0; i < rht.Size(); i++)
683  {
684  if (rht[i] >= 0)
685  {
687  }
688  }
689 
690  group_stria.MakeJ();
691  nstrias = 0;
692  for (int i = 0; i < rht.Size(); i++)
693  {
694  if (rht[i] >= 0)
695  {
696  group_stria.AddConnection(rht[i], nstrias++);
697  }
698  }
700 }
701 
702 void ParSubMesh::BuildSharedVerticesMapping(const int nsverts,
703  const Array<int>& rhvtx)
704 {
705  svert_lvert.Reserve(nsverts);
706 
707  for (int g = 1, sv = 0; g < parent_.GetNGroups(); g++)
708  {
709  for (int gv = 0; gv < parent_.GroupNVertices(g); gv++, sv++)
710  {
711  // Returns the parents local vertex id
712  int plvtx = parent_.GroupVertex(g, gv);
713  int submesh_vtx_id = parent_to_submesh_vertex_ids_[plvtx];
714  if ((submesh_vtx_id == -1) || (rhvtx[sv] == -1))
715  {
716  // parent shared vertex is not in SubMesh or is not shared
717  }
718  else
719  {
720  svert_lvert.Append(submesh_vtx_id);
721  }
722  }
723  }
724 }
725 
726 void ParSubMesh::BuildSharedEdgesMapping(const int sedges_ct,
727  const Array<int>& rhe)
728 {
729  shared_edges.Reserve(sedges_ct);
730  sedge_ledge.Reserve(sedges_ct);
731 
732  for (int g = 1, se = 0; g < parent_.GetNGroups(); g++)
733  {
734  for (int ge = 0; ge < parent_.GroupNEdges(g); ge++, se++)
735  {
736  int ple, o;
737  parent_.GroupEdge(g, ge, ple, o);
738  int submesh_edge_id = parent_to_submesh_edge_ids_[ple];
739  if ((submesh_edge_id == -1) || rhe[se] == -1)
740  {
741  // parent shared edge is not in SubMesh or is not shared
742  }
743  else
744  {
745  Array<int> vert;
746  GetEdgeVertices(submesh_edge_id, vert);
747 
748  shared_edges.Append(new Segment(vert[0], vert[1], 1));
749  sedge_ledge.Append(submesh_edge_id);
750  }
751  }
752  }
753 }
754 
755 void ParSubMesh::BuildSharedFacesMapping(const int nstrias,
756  const Array<int>& rht,
757  const int nsquads, const Array<int>& rhq)
758 {
759  shared_trias.Reserve(nstrias);
760  shared_quads.Reserve(nsquads);
761  sface_lface.Reserve(nstrias + nsquads);
762 
763  for (int g = 1, sq = 0; g < parent_.GetNGroups(); g++)
764  {
765  for (int gq = 0; gq < parent_.GroupNQuadrilaterals(g); gq++, sq++)
766  {
767  int plq, o;
768  parent_.GroupQuadrilateral(g, gq, plq, o);
769  int submesh_face_id = parent_to_submesh_face_ids_[plq];
770  if ((submesh_face_id == -1) || rhq[sq] == -1)
771  {
772  // parent shared face is not in SubMesh or is not shared
773  }
774  else
775  {
776  Array<int> vert;
777  GetFaceVertices(submesh_face_id, vert);
778 
779  shared_quads.Append(Vert4(vert[0], vert[1], vert[2], vert[3]));
780  sface_lface.Append(submesh_face_id);
781  }
782  }
783  }
784 
785  for (int g = 1, st = 0; g < parent_.GetNGroups(); g++)
786  {
787  for (int gt = 0; gt < parent_.GroupNTriangles(g); gt++, st++)
788  {
789  int plt, o;
790  parent_.GroupTriangle(g, gt, plt, o);
791  int submesh_face_id = parent_to_submesh_face_ids_[plt];
792  if ((submesh_face_id == -1) || rht[st] == -1)
793  {
794  // parent shared face is not in SubMesh or is not shared
795  }
796  else
797  {
798  Array<int> vert;
799  GetFaceVertices(submesh_face_id, vert);
800 
801  shared_trias.Append(Vert3(vert[0], vert[1], vert[2]));
802  sface_lface.Append(submesh_face_id);
803  }
804  }
805  }
806 }
807 
809 {
810  ParTransferMap map(src, dst);
811  map.Transfer(src, dst);
812 }
813 
815  const ParGridFunction &dst)
816 {
817  return ParTransferMap(src, dst);
818 }
819 
820 } // namespace mfem
821 
822 #endif // MFEM_USE_MPI
void Create(ListOfIntegerSets &groups, int mpitag)
Set up the group topology given the list of sets of shared entities.
static ParSubMesh CreateFromBoundary(const ParMesh &parent, Array< int > &boundary_attributes)
Create a surface ParSubMesh from it&#39;s parent.
Definition: psubmesh.cpp:32
Array< int > GetFaceToBdrElMap() const
Definition: mesh.cpp:1437
void GetSharedVertexCommunicator(int ordering, GroupCommunicator &svert_comm) const
Get the shared vertices GroupCommunicator.
Definition: pmesh.cpp:1661
int NRanks
Definition: pmesh.hpp:38
void GetSharedQuadCommunicator(int ordering, GroupCommunicator &squad_comm) const
Get the shared face quadrilaterals GroupCommunicator.
Definition: pmesh.cpp:1685
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
Definition: table.cpp:81
void GetSharedTriCommunicator(int ordering, GroupCommunicator &stria_comm) const
Get the shared face triangles GroupCommunicator.
Definition: pmesh.cpp:1709
Array< Element * > boundary
Definition: mesh.hpp:91
int Dimension() const
Definition: mesh.hpp:1047
int NumOfEdges
Definition: mesh.hpp:70
Array< int > sface_lface
Definition: pmesh.hpp:78
void GetVertexToVertexTable(DSTable &) const
Definition: mesh.cpp:6372
bool Nonconforming() const
Definition: mesh.hpp:1729
int GetNeighborRank(int i) const
Return the MPI rank of neighbor &#39;i&#39;.
int GetNEdges() const
Return the number of edges.
Definition: mesh.hpp:942
Array< Vert3 > shared_trias
Definition: pmesh.hpp:65
void GroupEdge(int group, int i, int &edge, int &o) const
Definition: pmesh.cpp:1607
Array< Element * > faces
Definition: mesh.hpp:92
Array< int > sedge_ledge
Definition: pmesh.hpp:76
Table group_stria
Definition: pmesh.hpp:71
Subdomain representation of a topological parent in another ParMesh.
Definition: psubmesh.hpp:51
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition: mesh.hpp:933
void ExchangeFaceNbrData()
Definition: pmesh.cpp:2117
MPI_Comm MyComm
Definition: pmesh.hpp:37
void Finalize(bool refine=false, bool fix_orientation=false) override
Finalize the construction of a general Mesh.
Definition: pmesh.cpp:1516
static void Sum(OpData< T >)
Reduce operation Sum, instantiated for int and double.
Array< Element * > shared_edges
Definition: pmesh.hpp:61
int Append(const T &el)
Append element &#39;el&#39; to array, resize if necessary.
Definition: array.hpp:756
static ParSubMesh CreateFromDomain(const ParMesh &parent, Array< int > &domain_attributes)
Create a domain ParSubMesh from it&#39;s parent.
Definition: psubmesh.cpp:26
int GroupNVertices(int group) const
Definition: pmesh.hpp:395
int GroupVertex(int group, int i) const
Definition: pmesh.hpp:400
void AddConnection(int r, int c)
Definition: table.hpp:80
STable3D * GetElementToFaceTable(int ret_ftbl=0)
Definition: mesh.cpp:6839
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
Definition: mesh.cpp:6029
void GetFaceVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of face i.
Definition: mesh.hpp:1166
int GetNGroups() const
Definition: pmesh.hpp:392
ParTransferMap represents a mapping of degrees of freedom from a source ParGridFunction to a destinat...
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
Definition: array.hpp:159
const int * GetGroup(int g) const
Return a pointer to a list of neighbors for a given group. Neighbor 0 is the local processor...
int GetElementToEdgeTable(Table &, Array< int > &)
Definition: mesh.cpp:6397
void GetSharedEdgeCommunicator(int ordering, GroupCommunicator &sedge_comm) const
Get the shared edges GroupCommunicator.
Definition: pmesh.cpp:1637
int NumOfBdrElements
Definition: mesh.hpp:69
Table * el_to_edge
Definition: mesh.hpp:220
MPI_Comm GetComm() const
Definition: pmesh.hpp:351
Array< Vert4 > shared_quads
Definition: pmesh.hpp:66
int GroupNTriangles(int group) const
Definition: pmesh.hpp:397
int GetMyRank() const
Definition: pmesh.hpp:353
int GetBdrAttribute(int i) const
Return the attribute of boundary element i.
Definition: mesh.hpp:1550
void Transfer(const ParGridFunction &src, ParGridFunction &dst) const
Transfer the source ParGridFunction to the destination ParGridFunction.
static const int GENERATED_ATTRIBUTE
Definition: submesh.hpp:52
std::tuple< Array< int >, Array< int > > AddElementsToMesh(const Mesh &parent, Mesh &mesh, const Array< int > &attributes, bool from_boundary)
Given a Mesh parent and another Mesh mesh using the list of attributes in attributes, this function adds matching elements with those attributes from parent to mesh.
void FinalizeTopology(bool generate_bdr=true)
Finalize the construction of the secondary topology (connectivity) data of a Mesh.
Definition: mesh.cpp:2902
void AddAColumnInRow(int r)
Definition: table.hpp:77
GridFunction * GetNodes()
Return a pointer to the internal node GridFunction (may be NULL).
Definition: mesh.hpp:1610
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition: array.hpp:684
Array< int > BuildFaceMap(const Mesh &pm, const Mesh &sm, const Array< int > &parent_element_ids)
Given two meshes that have a parent to SubMesh relationship create a face map, using a SubMesh to par...
void InitMesh(int Dim_, int spaceDim_, int NVert, int NElem, int NBdrElem)
Begin construction of a mesh.
Definition: mesh.cpp:1595
void SetAttributes() override
Definition: pmesh.cpp:1580
void ShiftUpI()
Definition: table.cpp:115
int SpaceDimension() const
Definition: mesh.hpp:1048
Table * bel_to_edge
Definition: mesh.hpp:224
From
Indicator from which part of the parent Mesh the SubMesh is created.
Definition: submesh.hpp:46
Array< int > be_to_edge
Definition: mesh.hpp:223
int GetNRanks() const
Definition: pmesh.hpp:352
int GetGroupSize(int g) const
Get the number of processors in a group.
Table group_sedge
Definition: pmesh.hpp:70
static ParTransferMap CreateTransferMap(const ParGridFunction &src, const ParGridFunction &dst)
Create a Transfer Map object.
Definition: psubmesh.cpp:814
void MakeJ()
Definition: table.cpp:91
Table group_svert
Shared objects in each group.
Definition: pmesh.hpp:69
void SetCurvature(int order, bool discont=false, int space_dim=-1, int ordering=1) override
Set the curvature of the mesh nodes using the given polynomial degree.
Definition: pmesh.cpp:2056
bool IsBoundary() const
Return true if the face is a boundary face.
Definition: mesh.hpp:1459
ParSubMesh()=delete
int Size() const
Return the logical size of the array.
Definition: array.hpp:141
FaceInformation GetFaceInformation(int f) const
Definition: mesh.cpp:1131
int Dim
Definition: mesh.hpp:66
void SetComm(MPI_Comm comm)
Set the MPI communicator to &#39;comm&#39;.
int GetNFaces() const
Return the number of faces in a 3D mesh.
Definition: mesh.hpp:945
int GroupNEdges(int group) const
Definition: pmesh.hpp:396
Array< int > svert_lvert
Shared to local index mapping.
Definition: pmesh.hpp:75
int GroupNQuadrilaterals(int group) const
Definition: pmesh.hpp:398
void GetNodes(Vector &node_coord) const
Definition: mesh.cpp:7949
int MyRank
Definition: pmesh.hpp:38
int spaceDim
Definition: mesh.hpp:67
Class for parallel grid function.
Definition: pgridfunc.hpp:32
static void Transfer(const ParGridFunction &src, ParGridFunction &dst)
Transfer the dofs of a ParGridFunction.
Definition: psubmesh.cpp:808
void GroupQuadrilateral(int group, int i, int &face, int &o) const
Definition: pmesh.cpp:1626
Array< int > be_to_face
Definition: mesh.hpp:225
GroupTopology gtopo
Definition: pmesh.hpp:375
void GroupTriangle(int group, int i, int &face, int &o) const
Definition: pmesh.cpp:1615
Class for parallel meshes.
Definition: pmesh.hpp:32
Table group_squad
Definition: pmesh.hpp:72
int NumOfFaces
Definition: mesh.hpp:70