MFEM  v4.5.1
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
psubmesh.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2022, 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  Array<int> &be2face = (Dim == 2) ? be_to_edge : be_to_face;
171 
172  if (Dim == 3)
173  {
174  // In 3D we check for `bel_to_edge`. It shouldn't have been set
175  // previously.
176  delete bel_to_edge;
177  bel_to_edge = nullptr;
178  }
179 
180  NumOfBdrElements = 0;
181  for (int i = 0; i < NumOfFaces; i++)
182  {
184  {
186  }
187  }
188 
189  boundary.SetSize(NumOfBdrElements);
190  be2face.SetSize(NumOfBdrElements);
191  Array<int> parent_face_to_be;
192  if (Dim == 3)
193  {
194  parent_face_to_be = parent.GetFaceToBdrElMap();
195  }
196  for (int i = 0, j = 0; i < NumOfFaces; i++)
197  {
198  if (GetFaceInformation(i).IsBoundary())
199  {
200  boundary[j] = faces[i]->Duplicate(this);
201 
202  if (Dim == 3)
203  {
204  int pbeid = parent_face_to_be[parent_face_ids_[i]];
205  if (pbeid != -1)
206  {
207  boundary[j]->SetAttribute(parent.GetBdrAttribute(pbeid));
208  }
209  else
210  {
211  boundary[j]->SetAttribute(SubMesh::GENERATED_ATTRIBUTE);
212  }
213  }
214  be2face[j++] = i;
215  }
216  }
217  }
218 
219  if (Dim == 3)
220  {
222  }
223 
224  // If the parent ParMesh has nodes and therefore is defined on a higher order
225  // geometry, we define this ParSubMesh as a curved ParSubMesh and transfer
226  // the GridFunction from the parent ParMesh to the ParSubMesh.
227  const GridFunction *parent_nodes = parent_.GetNodes();
228  if (parent_nodes)
229  {
230  const FiniteElementSpace *parent_fes = parent_nodes->FESpace();
231 
232  SetCurvature(
233  parent_fes->FEColl()->GetOrder(),
234  parent_fes->IsDGSpace(),
235  spaceDim,
236  parent_fes->GetOrdering());
237 
238  const ParGridFunction* pn = dynamic_cast<const ParGridFunction*>
239  (parent_.GetNodes());
240  MFEM_ASSERT(pn,
241  "Internal error. Object is supposed to be ParGridFunction.");
242 
243  ParGridFunction* n = dynamic_cast<ParGridFunction*>
244  (this->GetNodes());
245  MFEM_ASSERT(n,
246  "Internal error. Object is supposed to be ParGridFunction.");
247 
248  Transfer(*pn, *n);
249  }
250 
251  el_to_edge = new Table;
253 
254  SetAttributes();
255  Finalize();
256 }
257 
258 void ParSubMesh::FindSharedVerticesRanks(Array<int> &rhvtx)
259 {
260  // create a GroupCommunicator on the shared vertices
261  GroupCommunicator svert_comm(parent_.gtopo);
262  parent_.GetSharedVertexCommunicator(svert_comm);
263  // Number of shared vertices
264  int nsvtx = svert_comm.GroupLDofTable().Size_of_connections();
265 
266  rhvtx.SetSize(nsvtx);
267  rhvtx = 0;
268 
269  // On each rank of the group, locally determine if the shared vertex is in
270  // the SubMesh.
271  for (int g = 1, sv = 0; g < parent_.GetNGroups(); g++)
272  {
273  const int group_sz = parent_.gtopo.GetGroupSize(g);
274  MFEM_VERIFY((unsigned int)group_sz <= 8*sizeof(int), // 32
275  "Group size too large. Groups with more than 32 ranks are not supported, yet.");
276  const int* group_lproc = parent_.gtopo.GetGroup(g);
277 
278  const int* my_group_id_ptr = std::find(group_lproc, group_lproc+group_sz, 0);
279  MFEM_ASSERT(my_group_id_ptr != group_lproc+group_sz, "internal error");
280 
281  const int my_group_id = my_group_id_ptr-group_lproc;
282 
283  for (int gv = 0; gv < parent_.GroupNVertices(g); gv++, sv++)
284  {
285  int plvtx = parent_.GroupVertex(g, gv);
286  int submesh_vertex_id = parent_to_submesh_vertex_ids_[plvtx];
287  if (submesh_vertex_id != -1)
288  {
289  rhvtx[sv] |= 1 << my_group_id;
290  }
291  }
292  }
293 
294  // Compute the sum on the root rank and broadcast the result to all ranks.
295  svert_comm.Reduce(rhvtx, GroupCommunicator::Sum);
296  svert_comm.Bcast<int>(rhvtx, 0);
297 }
298 
299 void ParSubMesh::FindSharedEdgesRanks(Array<int> &rhe)
300 {
301  // create a GroupCommunicator on the shared edges
302  GroupCommunicator sedge_comm(parent_.gtopo);
303  parent_.GetSharedEdgeCommunicator(sedge_comm);
304 
305  int nsedges = sedge_comm.GroupLDofTable().Size_of_connections();
306 
307  // see rhvtx description
308  rhe.SetSize(nsedges);
309  rhe = 0;
310 
311  // On each rank of the group, locally determine if the shared edge is in
312  // the SubMesh.
313  for (int g = 1, se = 0; g < parent_.GetNGroups(); g++)
314  {
315  const int group_sz = parent_.gtopo.GetGroupSize(g);
316  MFEM_VERIFY((unsigned int)group_sz <= 8*sizeof(int), // 32
317  "Group size too large. Groups with more than 32 ranks are not supported, yet.");
318  const int* group_lproc = parent_.gtopo.GetGroup(g);
319 
320  const int* my_group_id_ptr = std::find(group_lproc, group_lproc+group_sz, 0);
321  MFEM_ASSERT(my_group_id_ptr != group_lproc+group_sz, "internal error");
322 
323  // rank id inside this group
324  const int my_group_id = my_group_id_ptr-group_lproc;
325 
326  for (int ge = 0; ge < parent_.GroupNEdges(g); ge++, se++)
327  {
328  int ple, o;
329  parent_.GroupEdge(g, ge, ple, o);
330  int submesh_edge_id = parent_to_submesh_edge_ids_[ple];
331  if (submesh_edge_id != -1)
332  {
333  rhe[se] |= 1 << my_group_id;
334  }
335  }
336  }
337 
338  // Compute the sum on the root rank and broadcast the result to all ranks.
339  sedge_comm.Reduce(rhe, GroupCommunicator::Sum);
340  sedge_comm.Bcast<int>(rhe, 0);
341 }
342 
343 void ParSubMesh::FindSharedFacesRanks(Array<int>& rht, Array<int> &rhq)
344 {
345  GroupCommunicator squad_comm(parent_.gtopo);
346  parent_.GetSharedQuadCommunicator(squad_comm);
347 
348  int nsquad = squad_comm.GroupLDofTable().Size_of_connections();
349 
350  rhq.SetSize(nsquad);
351  rhq = 0;
352 
353  for (int g = 1, sq = 0; g < parent_.GetNGroups(); g++)
354  {
355  for (int gq = 0; gq < parent_.GroupNQuadrilaterals(g); gq++, sq++)
356  {
357  // Group size of a shared face is always 2
358 
359  int plq, o;
360  parent_.GroupQuadrilateral(g, gq, plq, o);
361  int submesh_face_id = parent_to_submesh_face_ids_[plq];
362  if (submesh_face_id != -1)
363  {
364  rhq[sq] = 1;
365  }
366  }
367  }
368 
369  // Compute the sum on the root rank and broadcast the result to all ranks.
370  squad_comm.Reduce(rhq, GroupCommunicator::Sum);
371  squad_comm.Bcast<int>(rhq, 0);
372 
373  GroupCommunicator stria_comm(parent_.gtopo);
374  parent_.GetSharedTriCommunicator(stria_comm);
375 
376  int nstria = stria_comm.GroupLDofTable().Size_of_connections();
377 
378  rht.SetSize(nstria);
379  rht = 0;
380 
381  for (int g = 1, st = 0; g < parent_.GetNGroups(); g++)
382  {
383  for (int gt = 0; gt < parent_.GroupNTriangles(g); gt++, st++)
384  {
385  // Group size of a shared face is always 2
386 
387  int plt, o;
388  parent_.GroupTriangle(g, gt, plt, o);
389  int submesh_face_id = parent_to_submesh_face_ids_[plt];
390  if (submesh_face_id != -1)
391  {
392  rht[st] = 1;
393  }
394  }
395  }
396 
397  // Compute the sum on the root rank and broadcast the result to all ranks.
398  stria_comm.Reduce(rht, GroupCommunicator::Sum);
399  stria_comm.Bcast<int>(rht, 0);
400 }
401 
402 
403 void ParSubMesh::AppendSharedVerticesGroups(ListOfIntegerSets &groups,
404  Array<int> &rhvtx)
405 {
406  IntegerSet group;
407 
408  for (int g = 1, sv = 0; g < parent_.GetNGroups(); g++)
409  {
410  const int group_sz = parent_.gtopo.GetGroupSize(g);
411  MFEM_VERIFY((unsigned int)group_sz <= 8*sizeof(int), // 32
412  "Group size too large. Groups with more than 32 ranks are not supported, yet.");
413  const int* group_lproc = parent_.gtopo.GetGroup(g);
414 
415  const int* my_group_id_ptr = std::find(group_lproc, group_lproc+group_sz, 0);
416  MFEM_ASSERT(my_group_id_ptr != group_lproc+group_sz, "internal error");
417 
418  const int my_group_id = my_group_id_ptr-group_lproc;
419 
420  for (int gv = 0; gv < parent_.GroupNVertices(g); gv++, sv++)
421  {
422  // Returns the parents local vertex id
423  int plvtx = parent_.GroupVertex(g, gv);
424  int submesh_vtx = parent_to_submesh_vertex_ids_[plvtx];
425 
426  // Reusing the `rhvtx` array as shared vertex to group array.
427  if (submesh_vtx == -1)
428  {
429  // parent shared vertex is not in SubMesh
430  rhvtx[sv] = -1;
431  }
432  else if (rhvtx[sv] & ~(1 << my_group_id))
433  {
434  // shared vertex is present on this rank and others
435  MFEM_ASSERT(rhvtx[sv] & (1 << my_group_id), "error again");
436 
437  // determine which other ranks have the shared vertex
438  Array<int> &ranks = group;
439  ranks.SetSize(0);
440  for (int i = 0; i < group_sz; i++)
441  {
442  if ((rhvtx[sv] >> i) & 1)
443  {
444  ranks.Append(parent_.gtopo.GetNeighborRank(group_lproc[i]));
445  }
446  }
447  MFEM_ASSERT(ranks.Size() >= 2, "internal error");
448 
449  rhvtx[sv] = groups.Insert(group) - 1;
450  }
451  else
452  {
453  // previously shared vertex is only present on this rank
454  rhvtx[sv] = -1;
455  }
456  }
457  }
458 }
459 
460 void ParSubMesh::AppendSharedEdgesGroups(ListOfIntegerSets &groups,
461  Array<int> &rhe)
462 {
463  IntegerSet group;
464 
465  for (int g = 1, se = 0; g < parent_.GetNGroups(); g++)
466  {
467  const int group_sz = parent_.gtopo.GetGroupSize(g);
468  MFEM_VERIFY((unsigned int)group_sz <= 8*sizeof(int), // 32
469  "Group size too large. Groups with more than 32 ranks are not supported, yet.");
470  const int* group_lproc = parent_.gtopo.GetGroup(g);
471 
472  const int* my_group_id_ptr = std::find(group_lproc, group_lproc+group_sz, 0);
473  MFEM_ASSERT(my_group_id_ptr != group_lproc+group_sz, "internal error");
474 
475  const int my_group_id = my_group_id_ptr-group_lproc;
476 
477  for (int ge = 0; ge < parent_.GroupNEdges(g); ge++, se++)
478  {
479  int ple, o;
480  parent_.GroupEdge(g, ge, ple, o);
481  int submesh_edge = parent_to_submesh_edge_ids_[ple];
482 
483  // Reusing the `rhe` array as shared edge to group array.
484  if (submesh_edge == -1)
485  {
486  // parent shared edge is not in SubMesh
487  rhe[se] = -1;
488  }
489  else if (rhe[se] & ~(1 << my_group_id))
490  {
491  // shared edge is present on this rank and others
492 
493  // determine which other ranks have the shared edge
494  Array<int> &ranks = group;
495  ranks.SetSize(0);
496  for (int i = 0; i < group_sz; i++)
497  {
498  if ((rhe[se] >> i) & 1)
499  {
500  ranks.Append(parent_.gtopo.GetNeighborRank(group_lproc[i]));
501  }
502  }
503  MFEM_ASSERT(ranks.Size() >= 2, "internal error");
504 
505  rhe[se] = groups.Insert(group) - 1;
506  }
507  else
508  {
509  // previously shared edge is only present on this rank
510  rhe[se] = -1;
511  }
512  }
513  }
514 }
515 
516 void ParSubMesh::AppendSharedFacesGroups(ListOfIntegerSets &groups,
517  Array<int>& rht, Array<int> &rhq)
518 {
519  IntegerSet quad_group;
520 
521  for (int g = 1, sq = 0; g < parent_.GetNGroups(); g++)
522  {
523  const int* group_lproc = parent_.gtopo.GetGroup(g);
524  for (int gq = 0; gq < parent_.GroupNQuadrilaterals(g); gq++, sq++)
525  {
526  const int group_sz = parent_.gtopo.GetGroupSize(g);
527  MFEM_ASSERT(group_sz == 2, "internal error");
528 
529  int plq, o;
530  parent_.GroupQuadrilateral(g, gq, plq, o);
531  int submesh_face_id = parent_to_submesh_face_ids_[plq];
532 
533  // Reusing the `rhq` array as shared face to group array.
534  if (submesh_face_id == -1)
535  {
536  // parent shared face is not in SubMesh
537  rhq[sq] = -1;
538  }
539  else if (rhq[sq] == group_sz)
540  {
541  // shared face is present on this rank and others
542 
543  // There can only be two ranks in this group sharing faces. Add
544  // all ranks to a new communication group.
545  Array<int> &ranks = quad_group;
546  ranks.SetSize(0);
547  ranks.Append(parent_.gtopo.GetNeighborRank(group_lproc[0]));
548  ranks.Append(parent_.gtopo.GetNeighborRank(group_lproc[1]));
549 
550  rhq[sq] = groups.Insert(quad_group) - 1;
551  }
552  else
553  {
554  // previously shared edge is only present on this rank
555  rhq[sq] = -1;
556  }
557  }
558  }
559 
560  IntegerSet tria_group;
561 
562  for (int g = 1, st = 0; g < parent_.GetNGroups(); g++)
563  {
564  const int* group_lproc = parent_.gtopo.GetGroup(g);
565  for (int gt = 0; gt < parent_.GroupNTriangles(g); gt++, st++)
566  {
567  const int group_sz = parent_.gtopo.GetGroupSize(g);
568  MFEM_ASSERT(group_sz == 2, "internal error");
569 
570  int plt, o;
571  parent_.GroupTriangle(g, gt, plt, o);
572  int submesh_face_id = parent_to_submesh_face_ids_[plt];
573 
574  // Reusing the `rht` array as shared face to group array.
575  if (submesh_face_id == -1)
576  {
577  // parent shared face is not in SubMesh
578  rht[st] = -1;
579  }
580  else if (rht[st] == group_sz)
581  {
582  // shared face is present on this rank and others
583 
584  // There can only be two ranks in this group sharing faces. Add
585  // all ranks to a new communication group.
586  Array<int> &ranks = tria_group;
587  ranks.SetSize(0);
588  ranks.Append(parent_.gtopo.GetNeighborRank(group_lproc[0]));
589  ranks.Append(parent_.gtopo.GetNeighborRank(group_lproc[1]));
590 
591  rht[st] = groups.Insert(tria_group) - 1;
592  }
593  else
594  {
595  // previously shared edge is only present on this rank
596  rht[st] = -1;
597  }
598  }
599  }
600 }
601 
602 void ParSubMesh::BuildVertexGroup(int ngroups, const Array<int>& rhvtx,
603  int& nsverts)
604 {
605  group_svert.MakeI(ngroups);
606  for (int i = 0; i < rhvtx.Size(); i++)
607  {
608  if (rhvtx[i] >= 0)
609  {
610  group_svert.AddAColumnInRow(rhvtx[i]);
611  }
612  }
613 
614  group_svert.MakeJ();
615  nsverts = 0;
616  for (int i = 0; i < rhvtx.Size(); i++)
617  {
618  if (rhvtx[i] >= 0)
619  {
620  group_svert.AddConnection(rhvtx[i], nsverts++);
621  }
622  }
624 }
625 
626 void ParSubMesh::BuildEdgeGroup(int ngroups, const Array<int>& rhe,
627  int& nsedges)
628 {
629  group_sedge.MakeI(ngroups);
630  for (int i = 0; i < rhe.Size(); i++)
631  {
632  if (rhe[i] >= 0)
633  {
635  }
636  }
637 
638  group_sedge.MakeJ();
639  nsedges = 0;
640  for (int i = 0; i < rhe.Size(); i++)
641  {
642  if (rhe[i] >= 0)
643  {
644  group_sedge.AddConnection(rhe[i], nsedges++);
645  }
646  }
648 }
649 
650 void ParSubMesh::BuildFaceGroup(int ngroups, const Array<int>& rht,
651  int& nstrias, const Array<int>& rhq, int& nsquads)
652 {
653  group_squad.MakeI(ngroups);
654  for (int i = 0; i < rhq.Size(); i++)
655  {
656  if (rhq[i] >= 0)
657  {
659  }
660  }
661 
662  group_squad.MakeJ();
663  nsquads = 0;
664  for (int i = 0; i < rhq.Size(); i++)
665  {
666  if (rhq[i] >= 0)
667  {
668  group_squad.AddConnection(rhq[i], nsquads++);
669  }
670  }
672 
673  group_stria.MakeI(ngroups);
674  for (int i = 0; i < rht.Size(); i++)
675  {
676  if (rht[i] >= 0)
677  {
679  }
680  }
681 
682  group_stria.MakeJ();
683  nstrias = 0;
684  for (int i = 0; i < rht.Size(); i++)
685  {
686  if (rht[i] >= 0)
687  {
688  group_stria.AddConnection(rht[i], nstrias++);
689  }
690  }
692 }
693 
694 void ParSubMesh::BuildSharedVerticesMapping(const int nsverts,
695  const Array<int>& rhvtx)
696 {
697  svert_lvert.Reserve(nsverts);
698 
699  for (int g = 1, sv = 0; g < parent_.GetNGroups(); g++)
700  {
701  for (int gv = 0; gv < parent_.GroupNVertices(g); gv++, sv++)
702  {
703  // Returns the parents local vertex id
704  int plvtx = parent_.GroupVertex(g, gv);
705  int submesh_vtx_id = parent_to_submesh_vertex_ids_[plvtx];
706  if ((submesh_vtx_id == -1) || (rhvtx[sv] == -1))
707  {
708  // parent shared vertex is not in SubMesh or is not shared
709  }
710  else
711  {
712  svert_lvert.Append(submesh_vtx_id);
713  }
714  }
715  }
716 }
717 
718 void ParSubMesh::BuildSharedEdgesMapping(const int sedges_ct,
719  const Array<int>& rhe)
720 {
721  shared_edges.Reserve(sedges_ct);
722  sedge_ledge.Reserve(sedges_ct);
723 
724  for (int g = 1, se = 0; g < parent_.GetNGroups(); g++)
725  {
726  for (int ge = 0; ge < parent_.GroupNEdges(g); ge++, se++)
727  {
728  int ple, o;
729  parent_.GroupEdge(g, ge, ple, o);
730  int submesh_edge_id = parent_to_submesh_edge_ids_[ple];
731  if ((submesh_edge_id == -1) || rhe[se] == -1)
732  {
733  // parent shared edge is not in SubMesh or is not shared
734  }
735  else
736  {
737  Array<int> vert;
738  GetEdgeVertices(submesh_edge_id, vert);
739 
740  shared_edges.Append(new Segment(vert[0], vert[1], 1));
741  sedge_ledge.Append(submesh_edge_id);
742  }
743  }
744  }
745 }
746 
747 void ParSubMesh::BuildSharedFacesMapping(const int nstrias,
748  const Array<int>& rht,
749  const int nsquads, const Array<int>& rhq)
750 {
751  shared_trias.Reserve(nstrias);
752  shared_quads.Reserve(nsquads);
753  sface_lface.Reserve(nstrias + nsquads);
754 
755  for (int g = 1, sq = 0; g < parent_.GetNGroups(); g++)
756  {
757  for (int gq = 0; gq < parent_.GroupNQuadrilaterals(g); gq++, sq++)
758  {
759  int plq, o;
760  parent_.GroupQuadrilateral(g, gq, plq, o);
761  int submesh_face_id = parent_to_submesh_face_ids_[plq];
762  if ((submesh_face_id == -1) || rhq[sq] == -1)
763  {
764  // parent shared face is not in SubMesh or is not shared
765  }
766  else
767  {
768  Array<int> vert;
769  GetFaceVertices(submesh_face_id, vert);
770 
771  shared_quads.Append(Vert4(vert[0], vert[1], vert[2], vert[3]));
772  sface_lface.Append(submesh_face_id);
773  }
774  }
775  }
776 
777  for (int g = 1, st = 0; g < parent_.GetNGroups(); g++)
778  {
779  for (int gt = 0; gt < parent_.GroupNTriangles(g); gt++, st++)
780  {
781  int plt, o;
782  parent_.GroupTriangle(g, gt, plt, o);
783  int submesh_face_id = parent_to_submesh_face_ids_[plt];
784  if ((submesh_face_id == -1) || rht[st] == -1)
785  {
786  // parent shared face is not in SubMesh or is not shared
787  }
788  else
789  {
790  Array<int> vert;
791  GetFaceVertices(submesh_face_id, vert);
792 
793  shared_trias.Append(Vert3(vert[0], vert[1], vert[2]));
794  sface_lface.Append(submesh_face_id);
795  }
796  }
797  }
798 }
799 
801 {
802  ParTransferMap map(src, dst);
803  map.Transfer(src, dst);
804 }
805 
807  const ParGridFunction &dst)
808 {
809  return ParTransferMap(src, dst);
810 }
811 
812 } // namespace mfem
813 
814 #endif // MFEM_USE_MPI
void Create(ListOfIntegerSets &groups, int mpitag)
Set up the group topology given the list of sets of shared entities.
int Size() const
Return the logical size of the array.
Definition: array.hpp:138
void GroupQuadrilateral(int group, int i, int &face, int &o) const
Definition: pmesh.cpp:1626
static ParSubMesh CreateFromBoundary(const ParMesh &parent, Array< int > &boundary_attributes)
Create a surface ParSubMesh from it&#39;s parent.
Definition: psubmesh.cpp:32
FaceInformation GetFaceInformation(int f) const
Definition: mesh.cpp:1131
int GetBdrAttribute(int i) const
Return the attribute of boundary element i.
Definition: mesh.hpp:1486
int NRanks
Definition: pmesh.hpp:38
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
Definition: mesh.cpp:6016
int GroupNVertices(int group) const
Definition: pmesh.hpp:395
int GroupNEdges(int group) const
Definition: pmesh.hpp:396
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
Definition: table.cpp:81
int GroupNTriangles(int group) const
Definition: pmesh.hpp:397
Array< Element * > boundary
Definition: mesh.hpp:91
int GetNGroups() const
Definition: pmesh.hpp:392
void GetSharedVertexCommunicator(int ordering, GroupCommunicator &svert_comm) const
Get the shared vertices GroupCommunicator.
Definition: pmesh.cpp:1661
int NumOfEdges
Definition: mesh.hpp:70
int GetGroupSize(int g) const
Get the number of processors in a group.
Array< int > sface_lface
Definition: pmesh.hpp:78
const int * GetGroup(int g) const
Return a pointer to a list of neighbors for a given group. Neighbor 0 is the local processor...
void GetFaceVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of face i.
Definition: mesh.hpp:1127
Array< Vert3 > shared_trias
Definition: pmesh.hpp:65
Array< Element * > faces
Definition: mesh.hpp:92
void GetVertexToVertexTable(DSTable &) const
Definition: mesh.cpp:6331
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 GetNRanks() const
Definition: pmesh.hpp:352
void ExchangeFaceNbrData()
Definition: pmesh.cpp:2117
bool Nonconforming() const
Definition: mesh.hpp:1651
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:751
static ParSubMesh CreateFromDomain(const ParMesh &parent, Array< int > &domain_attributes)
Create a domain ParSubMesh from it&#39;s parent.
Definition: psubmesh.cpp:26
void AddConnection(int r, int c)
Definition: table.hpp:80
STable3D * GetElementToFaceTable(int ret_ftbl=0)
Definition: mesh.cpp:6798
void Transfer(const ParGridFunction &src, ParGridFunction &dst) const
Transfer the source ParGridFunction to the destination ParGridFunction.
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:156
int GetElementToEdgeTable(Table &, Array< int > &)
Definition: mesh.cpp:6356
bool IsBoundary() const
Return true if the face is a boundary face.
Definition: mesh.hpp:1398
int Dimension() const
Definition: mesh.hpp:1006
int NumOfBdrElements
Definition: mesh.hpp:69
Table * el_to_edge
Definition: mesh.hpp:220
Array< Vert4 > shared_quads
Definition: pmesh.hpp:66
int SpaceDimension() const
Definition: mesh.hpp:1007
int GroupNQuadrilaterals(int group) const
Definition: pmesh.hpp:398
int GetMyRank() const
Definition: pmesh.hpp:353
MPI_Comm GetComm() const
Definition: pmesh.hpp:351
void GetSharedTriCommunicator(int ordering, GroupCommunicator &stria_comm) const
Get the shared face triangles GroupCommunicator.
Definition: pmesh.cpp:1709
static const int GENERATED_ATTRIBUTE
Definition: submesh.hpp:52
int GetNeighborRank(int i) const
Return the MPI rank of neighbor &#39;i&#39;.
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:2890
void AddAColumnInRow(int r)
Definition: table.hpp:77
GridFunction * GetNodes()
Return a pointer to the internal node GridFunction (may be NULL).
Definition: mesh.hpp:1541
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition: array.hpp:679
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:1590
void SetAttributes() override
Definition: pmesh.cpp:1580
void ShiftUpI()
Definition: table.cpp:115
Table * bel_to_edge
Definition: mesh.hpp:224
void GetSharedEdgeCommunicator(int ordering, GroupCommunicator &sedge_comm) const
Get the shared edges GroupCommunicator.
Definition: pmesh.cpp:1637
From
Indicator from which part of the parent Mesh the SubMesh is created.
Definition: submesh.hpp:46
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition: mesh.hpp:920
Array< int > be_to_edge
Definition: mesh.hpp:223
void GroupEdge(int group, int i, int &edge, int &o) const
Definition: pmesh.cpp:1607
void GetSharedQuadCommunicator(int ordering, GroupCommunicator &squad_comm) const
Get the shared face quadrilaterals GroupCommunicator.
Definition: pmesh.cpp:1685
Table group_sedge
Definition: pmesh.hpp:70
static ParTransferMap CreateTransferMap(const ParGridFunction &src, const ParGridFunction &dst)
Create a Transfer Map object.
Definition: psubmesh.cpp:806
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
Definition: pmesh.cpp:2056
void GroupTriangle(int group, int i, int &face, int &o) const
Definition: pmesh.cpp:1615
ParSubMesh()=delete
int GroupVertex(int group, int i) const
Definition: pmesh.hpp:400
int Dim
Definition: mesh.hpp:66
void SetComm(MPI_Comm comm)
Set the MPI communicator to &#39;comm&#39;.
int GetNEdges() const
Return the number of edges.
Definition: mesh.hpp:929
int GetNFaces() const
Return the number of faces in a 3D mesh.
Definition: mesh.hpp:932
void GetNodes(Vector &node_coord) const
Definition: mesh.cpp:7908
Array< int > GetFaceToBdrElMap() const
Definition: mesh.cpp:1437
Array< int > svert_lvert
Shared to local index mapping.
Definition: pmesh.hpp:75
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:800
Array< int > be_to_face
Definition: mesh.hpp:225
GroupTopology gtopo
Definition: pmesh.hpp:375
Class for parallel meshes.
Definition: pmesh.hpp:32
Table group_squad
Definition: pmesh.hpp:72
int NumOfFaces
Definition: mesh.hpp:70