MFEM  v3.4
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
pmesh.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
2 // the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
3 // reserved. See file COPYRIGHT for details.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability see http://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the GNU Lesser General Public License (as published by the Free
10 // Software Foundation) version 2.1 dated February 1999.
11 
12 #include "../config/config.hpp"
13 
14 #ifdef MFEM_USE_MPI
15 
16 #include "mesh_headers.hpp"
17 #include "../fem/fem.hpp"
18 #include "../general/sets.hpp"
19 #include "../general/sort_pairs.hpp"
20 #include "../general/text.hpp"
21 #include "../general/globals.hpp"
22 
23 #include <iostream>
24 using namespace std;
25 
26 namespace mfem
27 {
28 
29 ParMesh::ParMesh(const ParMesh &pmesh, bool copy_nodes)
30  : Mesh(pmesh, false),
31  group_svert(pmesh.group_svert),
32  group_sedge(pmesh.group_sedge),
33  group_sface(pmesh.group_sface),
34  gtopo(pmesh.gtopo)
35 {
36  MyComm = pmesh.MyComm;
37  NRanks = pmesh.NRanks;
38  MyRank = pmesh.MyRank;
39 
40  // Duplicate the shared_edges
41  shared_edges.SetSize(pmesh.shared_edges.Size());
42  for (int i = 0; i < shared_edges.Size(); i++)
43  {
44  shared_edges[i] = pmesh.shared_edges[i]->Duplicate(this);
45  }
46 
47  // Duplicate the shared_faces
48  shared_faces.SetSize(pmesh.shared_faces.Size());
49  for (int i = 0; i < shared_faces.Size(); i++)
50  {
51  shared_faces[i] = pmesh.shared_faces[i]->Duplicate(this);
52  }
53 
54  // Copy the shared-to-local index Arrays
58 
59  // Do not copy face-neighbor data (can be generated if needed)
60  have_face_nbr_data = false;
61 
62  // If pmesh has a ParNURBSExtension, it was copied by the Mesh copy ctor, so
63  // there is no need to do anything here.
64 
65  MFEM_VERIFY(pmesh.pncmesh == NULL,
66  "copy of parallel non-conforming meshes is not implemented");
67  pncmesh = NULL;
68 
69  // Copy the Nodes as a ParGridFunction, including the FiniteElementCollection
70  // and the FiniteElementSpace (as a ParFiniteElementSpace)
71  if (pmesh.Nodes && copy_nodes)
72  {
73  FiniteElementSpace *fes = pmesh.Nodes->FESpace();
74  const FiniteElementCollection *fec = fes->FEColl();
75  FiniteElementCollection *fec_copy =
77  ParFiniteElementSpace *pfes_copy =
78  new ParFiniteElementSpace(*fes, *this, fec_copy);
79  Nodes = new ParGridFunction(pfes_copy);
80  Nodes->MakeOwner(fec_copy);
81  *Nodes = *pmesh.Nodes;
82  own_nodes = 1;
83  }
84 }
85 
86 ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
87  int part_method)
88  : gtopo(comm)
89 {
90  int i, j;
91  int *partitioning;
92  Array<bool> activeBdrElem;
93 
94  MyComm = comm;
95  MPI_Comm_size(MyComm, &NRanks);
96  MPI_Comm_rank(MyComm, &MyRank);
97 
98  if (mesh.Nonconforming())
99  {
100  pncmesh = new ParNCMesh(comm, *mesh.ncmesh);
101 
102  // save the element partitioning before Prune()
103  int* partition = new int[mesh.GetNE()];
104  for (int i = 0; i < mesh.GetNE(); i++)
105  {
106  partition[i] = pncmesh->InitialPartition(i);
107  }
108 
109  pncmesh->Prune();
110 
112  pncmesh->OnMeshUpdated(this);
113 
114  ncmesh = pncmesh;
115  meshgen = mesh.MeshGenerator();
116 
117  mesh.attributes.Copy(attributes);
119 
121 
122  if (mesh.GetNodes())
123  {
124  Nodes = new ParGridFunction(this, mesh.GetNodes(), partition);
125  own_nodes = 1;
126  }
127  delete [] partition;
128 
129  have_face_nbr_data = false;
130  return;
131  }
132 
133  Dim = mesh.Dim;
134  spaceDim = mesh.spaceDim;
135 
136  BaseGeom = mesh.BaseGeom;
137  BaseBdrGeom = mesh.BaseBdrGeom;
138 
139  ncmesh = pncmesh = NULL;
140 
141  if (partitioning_)
142  {
143  partitioning = partitioning_;
144  }
145  else
146  {
147  partitioning = mesh.GeneratePartitioning(NRanks, part_method);
148  }
149 
150  // re-enumerate the partitions to better map to actual processor
151  // interconnect topology !?
152 
153  Array<int> vert;
154  Array<int> vert_global_local(mesh.GetNV());
155  int vert_counter, element_counter, bdrelem_counter;
156 
157  // build vert_global_local
158  vert_global_local = -1;
159 
160  element_counter = 0;
161  vert_counter = 0;
162  for (i = 0; i < mesh.GetNE(); i++)
163  if (partitioning[i] == MyRank)
164  {
165  mesh.GetElementVertices(i, vert);
166  element_counter++;
167  for (j = 0; j < vert.Size(); j++)
168  if (vert_global_local[vert[j]] < 0)
169  {
170  vert_global_local[vert[j]] = vert_counter++;
171  }
172  }
173 
174  NumOfVertices = vert_counter;
175  NumOfElements = element_counter;
176  vertices.SetSize(NumOfVertices);
177 
178  // Re-enumerate the local vertices to preserve the global ordering.
179  for (i = vert_counter = 0; i < vert_global_local.Size(); i++)
180  if (vert_global_local[i] >= 0)
181  {
182  vert_global_local[i] = vert_counter++;
183  }
184 
185  // determine vertices
186  for (i = 0; i < vert_global_local.Size(); i++)
187  if (vert_global_local[i] >= 0)
188  {
189  vertices[vert_global_local[i]].SetCoords(mesh.SpaceDimension(),
190  mesh.GetVertex(i));
191  }
192 
193  // Determine elements, enumerating the local elements to preserve the global
194  // order. This is used, e.g. by the ParGridFunction ctor that takes a global
195  // GridFunction as input parameter.
196  element_counter = 0;
197  elements.SetSize(NumOfElements);
198  for (i = 0; i < mesh.GetNE(); i++)
199  if (partitioning[i] == MyRank)
200  {
201  elements[element_counter] = mesh.GetElement(i)->Duplicate(this);
202  int *v = elements[element_counter]->GetVertices();
203  int nv = elements[element_counter]->GetNVertices();
204  for (j = 0; j < nv; j++)
205  {
206  v[j] = vert_global_local[v[j]];
207  }
208  element_counter++;
209  }
210 
211  Table *edge_element = NULL;
212  if (mesh.NURBSext)
213  {
214  activeBdrElem.SetSize(mesh.GetNBE());
215  activeBdrElem = false;
216  }
217  // build boundary elements
218  if (Dim == 3)
219  {
220  NumOfBdrElements = 0;
221  for (i = 0; i < mesh.GetNBE(); i++)
222  {
223  int face, o, el1, el2;
224  mesh.GetBdrElementFace(i, &face, &o);
225  mesh.GetFaceElements(face, &el1, &el2);
226  if (partitioning[(o % 2 == 0 || el2 < 0) ? el1 : el2] == MyRank)
227  {
229  if (mesh.NURBSext)
230  {
231  activeBdrElem[i] = true;
232  }
233  }
234  }
235 
236  bdrelem_counter = 0;
237  boundary.SetSize(NumOfBdrElements);
238  for (i = 0; i < mesh.GetNBE(); i++)
239  {
240  int face, o, el1, el2;
241  mesh.GetBdrElementFace(i, &face, &o);
242  mesh.GetFaceElements(face, &el1, &el2);
243  if (partitioning[(o % 2 == 0 || el2 < 0) ? el1 : el2] == MyRank)
244  {
245  boundary[bdrelem_counter] = mesh.GetBdrElement(i)->Duplicate(this);
246  int *v = boundary[bdrelem_counter]->GetVertices();
247  int nv = boundary[bdrelem_counter]->GetNVertices();
248  for (j = 0; j < nv; j++)
249  {
250  v[j] = vert_global_local[v[j]];
251  }
252  bdrelem_counter++;
253  }
254  }
255  }
256  else if (Dim == 2)
257  {
258  edge_element = new Table;
259  Transpose(mesh.ElementToEdgeTable(), *edge_element, mesh.GetNEdges());
260 
261  NumOfBdrElements = 0;
262  for (i = 0; i < mesh.GetNBE(); i++)
263  {
264  int edge = mesh.GetBdrElementEdgeIndex(i);
265  int el1 = edge_element->GetRow(edge)[0];
266  if (partitioning[el1] == MyRank)
267  {
268  NumOfBdrElements++;
269  if (mesh.NURBSext)
270  {
271  activeBdrElem[i] = true;
272  }
273  }
274  }
275 
276  bdrelem_counter = 0;
277  boundary.SetSize(NumOfBdrElements);
278  for (i = 0; i < mesh.GetNBE(); i++)
279  {
280  int edge = mesh.GetBdrElementEdgeIndex(i);
281  int el1 = edge_element->GetRow(edge)[0];
282  if (partitioning[el1] == MyRank)
283  {
284  boundary[bdrelem_counter] = mesh.GetBdrElement(i)->Duplicate(this);
285  int *v = boundary[bdrelem_counter]->GetVertices();
286  int nv = boundary[bdrelem_counter]->GetNVertices();
287  for (j = 0; j < nv; j++)
288  {
289  v[j] = vert_global_local[v[j]];
290  }
291  bdrelem_counter++;
292  }
293  }
294  }
295  else if (Dim == 1)
296  {
297  NumOfBdrElements = 0;
298  for (i = 0; i < mesh.GetNBE(); i++)
299  {
300  int vert = mesh.boundary[i]->GetVertices()[0];
301  int el1, el2;
302  mesh.GetFaceElements(vert, &el1, &el2);
303  if (partitioning[el1] == MyRank)
304  {
306  }
307  }
308 
309  bdrelem_counter = 0;
310  boundary.SetSize(NumOfBdrElements);
311  for (i = 0; i < mesh.GetNBE(); i++)
312  {
313  int vert = mesh.boundary[i]->GetVertices()[0];
314  int el1, el2;
315  mesh.GetFaceElements(vert, &el1, &el2);
316  if (partitioning[el1] == MyRank)
317  {
318  boundary[bdrelem_counter] = mesh.GetBdrElement(i)->Duplicate(this);
319  int *v = boundary[bdrelem_counter]->GetVertices();
320  v[0] = vert_global_local[v[0]];
321  bdrelem_counter++;
322  }
323  }
324  }
325 
326  meshgen = mesh.MeshGenerator();
327 
328  mesh.attributes.Copy(attributes);
330 
331  // this is called by the default Mesh constructor
332  // InitTables();
333 
334  if (Dim > 1)
335  {
336  el_to_edge = new Table;
338  }
339  else
340  {
341  NumOfEdges = 0;
342  }
343 
344  STable3D *faces_tbl = NULL;
345  if (Dim == 3)
346  {
347  faces_tbl = GetElementToFaceTable(1);
348  }
349  else
350  {
351  NumOfFaces = 0;
352  }
353  GenerateFaces();
354 
355  ListOfIntegerSets groups;
356  IntegerSet group;
357 
358  // the first group is the local one
359  group.Recreate(1, &MyRank);
360  groups.Insert(group);
361 
362 #ifdef MFEM_DEBUG
363  if (Dim < 3 && mesh.GetNFaces() != 0)
364  {
365  mfem::err << "ParMesh::ParMesh (proc " << MyRank << ") : "
366  "(Dim < 3 && mesh.GetNFaces() != 0) is true!" << endl;
367  mfem_error();
368  }
369 #endif
370  // determine shared faces
371  int sface_counter = 0;
372  Array<int> face_group(mesh.GetNFaces());
373  for (i = 0; i < face_group.Size(); i++)
374  {
375  int el[2];
376  face_group[i] = -1;
377  mesh.GetFaceElements(i, &el[0], &el[1]);
378  if (el[1] >= 0)
379  {
380  el[0] = partitioning[el[0]];
381  el[1] = partitioning[el[1]];
382  if ((el[0] == MyRank && el[1] != MyRank) ||
383  (el[0] != MyRank && el[1] == MyRank))
384  {
385  group.Recreate(2, el);
386  face_group[i] = groups.Insert(group) - 1;
387  sface_counter++;
388  }
389  }
390  }
391 
392  // determine shared edges
393  int sedge_counter = 0;
394  if (!edge_element)
395  {
396  edge_element = new Table;
397  if (Dim == 1)
398  {
399  edge_element->SetDims(0,0);
400  }
401  else
402  {
403  Transpose(mesh.ElementToEdgeTable(), *edge_element, mesh.GetNEdges());
404  }
405  }
406  for (i = 0; i < edge_element->Size(); i++)
407  {
408  int me = 0, others = 0;
409  for (j = edge_element->GetI()[i]; j < edge_element->GetI()[i+1]; j++)
410  {
411  edge_element->GetJ()[j] = partitioning[edge_element->GetJ()[j]];
412  if (edge_element->GetJ()[j] == MyRank)
413  {
414  me = 1;
415  }
416  else
417  {
418  others = 1;
419  }
420  }
421 
422  if (me && others)
423  {
424  sedge_counter++;
425  group.Recreate(edge_element->RowSize(i), edge_element->GetRow(i));
426  edge_element->GetRow(i)[0] = groups.Insert(group) - 1;
427  }
428  else
429  {
430  edge_element->GetRow(i)[0] = -1;
431  }
432  }
433 
434  // determine shared vertices
435  int svert_counter = 0;
436  Table *vert_element = mesh.GetVertexToElementTable(); // we must delete this
437 
438  for (i = 0; i < vert_element->Size(); i++)
439  {
440  int me = 0, others = 0;
441  for (j = vert_element->GetI()[i]; j < vert_element->GetI()[i+1]; j++)
442  {
443  vert_element->GetJ()[j] = partitioning[vert_element->GetJ()[j]];
444  if (vert_element->GetJ()[j] == MyRank)
445  {
446  me = 1;
447  }
448  else
449  {
450  others = 1;
451  }
452  }
453 
454  if (me && others)
455  {
456  svert_counter++;
457  group.Recreate(vert_element->RowSize(i), vert_element->GetRow(i));
458  vert_element->GetI()[i] = groups.Insert(group) - 1;
459  }
460  else
461  {
462  vert_element->GetI()[i] = -1;
463  }
464  }
465 
466  // build group_sface
467  group_sface.MakeI(groups.Size()-1);
468 
469  for (i = 0; i < face_group.Size(); i++)
470  {
471  if (face_group[i] >= 0)
472  {
473  group_sface.AddAColumnInRow(face_group[i]);
474  }
475  }
476 
477  group_sface.MakeJ();
478 
479  sface_counter = 0;
480  for (i = 0; i < face_group.Size(); i++)
481  {
482  if (face_group[i] >= 0)
483  {
484  group_sface.AddConnection(face_group[i], sface_counter++);
485  }
486  }
487 
489 
490  // build group_sedge
491  group_sedge.MakeI(groups.Size()-1);
492 
493  for (i = 0; i < edge_element->Size(); i++)
494  {
495  if (edge_element->GetRow(i)[0] >= 0)
496  {
497  group_sedge.AddAColumnInRow(edge_element->GetRow(i)[0]);
498  }
499  }
500 
501  group_sedge.MakeJ();
502 
503  sedge_counter = 0;
504  for (i = 0; i < edge_element->Size(); i++)
505  {
506  if (edge_element->GetRow(i)[0] >= 0)
507  {
508  group_sedge.AddConnection(edge_element->GetRow(i)[0], sedge_counter++);
509  }
510  }
511 
513 
514  // build group_svert
515  group_svert.MakeI(groups.Size()-1);
516 
517  for (i = 0; i < vert_element->Size(); i++)
518  {
519  if (vert_element->GetI()[i] >= 0)
520  {
521  group_svert.AddAColumnInRow(vert_element->GetI()[i]);
522  }
523  }
524 
525  group_svert.MakeJ();
526 
527  svert_counter = 0;
528  for (i = 0; i < vert_element->Size(); i++)
529  {
530  if (vert_element->GetI()[i] >= 0)
531  {
532  group_svert.AddConnection(vert_element->GetI()[i], svert_counter++);
533  }
534  }
535 
537 
538  // build shared_faces and sface_lface
539  shared_faces.SetSize(sface_counter);
540  sface_lface. SetSize(sface_counter);
541 
542  if (Dim == 3)
543  {
544  sface_counter = 0;
545  for (i = 0; i < face_group.Size(); i++)
546  {
547  if (face_group[i] >= 0)
548  {
549  shared_faces[sface_counter] = mesh.GetFace(i)->Duplicate(this);
550  int *v = shared_faces[sface_counter]->GetVertices();
551  int nv = shared_faces[sface_counter]->GetNVertices();
552  for (j = 0; j < nv; j++)
553  {
554  v[j] = vert_global_local[v[j]];
555  }
556  switch (shared_faces[sface_counter]->GetType())
557  {
558  case Element::TRIANGLE:
559  sface_lface[sface_counter] = (*faces_tbl)(v[0], v[1], v[2]);
560  // mark the shared face for refinement by reorienting
561  // it according to the refinement flag in the tetrahedron
562  // to which this shared face belongs to.
563  {
564  int lface = sface_lface[sface_counter];
565  Tetrahedron *tet =
566  (Tetrahedron *)(elements[faces_info[lface].Elem1No]);
567  tet->GetMarkedFace(faces_info[lface].Elem1Inf/64, v);
568  // flip the shared face in the processor that owns the
569  // second element (in 'mesh')
570  {
571  int gl_el1, gl_el2;
572  mesh.GetFaceElements(i, &gl_el1, &gl_el2);
573  if (MyRank == partitioning[gl_el2])
574  {
575  std::swap(v[0], v[1]);
576  }
577  }
578  }
579  break;
581  sface_lface[sface_counter] =
582  (*faces_tbl)(v[0], v[1], v[2], v[3]);
583  break;
584  }
585  sface_counter++;
586  }
587  }
588 
589  delete faces_tbl;
590  }
591 
592  // build shared_edges and sedge_ledge
593  shared_edges.SetSize(sedge_counter);
594  sedge_ledge. SetSize(sedge_counter);
595 
596  {
597  DSTable v_to_v(NumOfVertices);
598  GetVertexToVertexTable(v_to_v);
599 
600  sedge_counter = 0;
601  for (i = 0; i < edge_element->Size(); i++)
602  {
603  if (edge_element->GetRow(i)[0] >= 0)
604  {
605  mesh.GetEdgeVertices(i, vert);
606 
607  shared_edges[sedge_counter] =
608  new Segment(vert_global_local[vert[0]],
609  vert_global_local[vert[1]], 1);
610 
611  if ((sedge_ledge[sedge_counter] =
612  v_to_v(vert_global_local[vert[0]],
613  vert_global_local[vert[1]])) < 0)
614  {
615  mfem::err << "\n\n\n" << MyRank << ": ParMesh::ParMesh: "
616  << "ERROR in v_to_v\n\n" << endl;
617  mfem_error();
618  }
619 
620  sedge_counter++;
621  }
622  }
623  }
624 
625  delete edge_element;
626 
627  // build svert_lvert
628  svert_lvert.SetSize(svert_counter);
629 
630  svert_counter = 0;
631  for (i = 0; i < vert_element->Size(); i++)
632  {
633  if (vert_element->GetI()[i] >= 0)
634  {
635  svert_lvert[svert_counter++] = vert_global_local[i];
636  }
637  }
638 
639  delete vert_element;
640 
641  // build the group communication topology
642  gtopo.Create(groups, 822);
643 
644  if (mesh.NURBSext)
645  {
646  MFEM_ASSERT(mesh.GetNodes() &&
647  mesh.GetNodes()->FESpace()->GetNURBSext() == mesh.NURBSext,
648  "invalid NURBS mesh");
649  NURBSext = new ParNURBSExtension(comm, mesh.NURBSext, partitioning,
650  activeBdrElem);
651  }
652 
653  if (mesh.GetNodes()) // curved mesh
654  {
655  if (!NURBSext)
656  {
657  Nodes = new ParGridFunction(this, mesh.GetNodes());
658  }
659  else
660  {
661  const FiniteElementSpace *glob_fes = mesh.GetNodes()->FESpace();
663  FiniteElementCollection::New(glob_fes->FEColl()->Name());
664  ParFiniteElementSpace *pfes =
665  new ParFiniteElementSpace(this, nfec, glob_fes->GetVDim(),
666  glob_fes->GetOrdering());
667  Nodes = new ParGridFunction(pfes);
668  Nodes->MakeOwner(nfec); // Nodes will own nfec and pfes
669  }
670  own_nodes = 1;
671 
672  Array<int> gvdofs, lvdofs;
673  Vector lnodes;
674  element_counter = 0;
675  for (i = 0; i < mesh.GetNE(); i++)
676  if (partitioning[i] == MyRank)
677  {
678  Nodes->FESpace()->GetElementVDofs(element_counter, lvdofs);
679  mesh.GetNodes()->FESpace()->GetElementVDofs(i, gvdofs);
680  mesh.GetNodes()->GetSubVector(gvdofs, lnodes);
681  Nodes->SetSubVector(lvdofs, lnodes);
682  element_counter++;
683  }
684  }
685 
686  if (partitioning_ == NULL)
687  {
688  delete [] partitioning;
689  }
690 
691  have_face_nbr_data = false;
692 }
693 
694 // protected method
696  : MyComm(pncmesh.MyComm)
697  , NRanks(pncmesh.NRanks)
698  , MyRank(pncmesh.MyRank)
699  , gtopo(MyComm)
700  , pncmesh(NULL)
701 {
702  Mesh::InitFromNCMesh(pncmesh);
703  have_face_nbr_data = false;
704 }
705 
706 ParMesh::ParMesh(MPI_Comm comm, istream &input)
707  : gtopo(comm)
708 {
709  MyComm = comm;
710  MPI_Comm_size(MyComm, &NRanks);
711  MPI_Comm_rank(MyComm, &MyRank);
712 
713  have_face_nbr_data = false;
714  pncmesh = NULL;
715 
716  string ident;
717 
718  // read the serial part of the mesh
719  int gen_edges = 1;
720 
721  // Tell Loader() to read up to 'mfem_serial_mesh_end' instead of
722  // 'mfem_mesh_end', as we have additional parallel mesh data to load in from
723  // the stream.
724  Loader(input, gen_edges, "mfem_serial_mesh_end");
725 
726  skip_comment_lines(input, '#');
727 
728  // read the group topology
729  input >> ident;
730  MFEM_VERIFY(ident == "communication_groups",
731  "input stream is not a parallel MFEM mesh");
732  gtopo.Load(input);
733 
734  skip_comment_lines(input, '#');
735 
736  DSTable *v_to_v = NULL;
737  STable3D *faces_tbl = NULL;
738  // read and set the sizes of svert_lvert, group_svert
739  {
740  int num_sverts;
741  input >> ident >> num_sverts; // total_shared_vertices
742  svert_lvert.SetSize(num_sverts);
743  group_svert.SetDims(GetNGroups()-1, num_sverts);
744  }
745  // read and set the sizes of sedge_ledge, group_sedge
746  if (Dim >= 2)
747  {
748  skip_comment_lines(input, '#');
749  int num_sedges;
750  input >> ident >> num_sedges; // total_shared_edges
751  sedge_ledge.SetSize(num_sedges);
752  shared_edges.SetSize(num_sedges);
753  group_sedge.SetDims(GetNGroups()-1, num_sedges);
754  v_to_v = new DSTable(NumOfVertices);
755  GetVertexToVertexTable(*v_to_v);
756  }
757  else
758  {
759  group_sedge.SetSize(GetNGroups()-1, 0); // create empty group_sedge
760  }
761  // read and set the sizes of sface_lface, group_sface
762  if (Dim >= 3)
763  {
764  skip_comment_lines(input, '#');
765  int num_sfaces;
766  input >> ident >> num_sfaces; // total_shared_faces
767  sface_lface.SetSize(num_sfaces);
768  shared_faces.SetSize(num_sfaces);
769  group_sface.SetDims(GetNGroups()-1, num_sfaces);
770  faces_tbl = GetFacesTable();
771  }
772  else
773  {
774  group_sface.SetSize(GetNGroups()-1, 0); // create empty group_sface
775  }
776 
777  // read, group by group, the contents of group_svert, svert_lvert,
778  // group_sedge, shared_edges, group_sface, shared_faces
779  //
780  // derive the contents of sedge_ledge, sface_lface
781  int svert_counter = 0, sedge_counter = 0, sface_counter = 0;
782  for (int gr = 1; gr < GetNGroups(); gr++)
783  {
784  int g;
785  input >> ident >> g; // group
786  if (g != gr)
787  {
788  mfem::err << "ParMesh::ParMesh : expecting group " << gr
789  << ", read group " << g << endl;
790  mfem_error();
791  }
792 
793  {
794  int nv;
795  input >> ident >> nv; // shared_vertices (in this group)
796  nv += svert_counter;
797  MFEM_VERIFY(nv <= group_svert.Size_of_connections(),
798  "incorrect number of total_shared_vertices");
799  group_svert.GetI()[gr] = nv;
800  for ( ; svert_counter < nv; svert_counter++)
801  {
802  group_svert.GetJ()[svert_counter] = svert_counter;
803  input >> svert_lvert[svert_counter];
804  }
805  }
806  if (Dim >= 2)
807  {
808  int ne, v[2];
809  input >> ident >> ne; // shared_edges (in this group)
810  ne += sedge_counter;
811  MFEM_VERIFY(ne <= group_sedge.Size_of_connections(),
812  "incorrect number of total_shared_edges");
813  group_sedge.GetI()[gr] = ne;
814  for ( ; sedge_counter < ne; sedge_counter++)
815  {
816  group_sedge.GetJ()[sedge_counter] = sedge_counter;
817  input >> v[0] >> v[1];
818  shared_edges[sedge_counter] = new Segment(v[0], v[1], 1);
819  sedge_ledge[sedge_counter] = (*v_to_v)(v[0], v[1]);
820  }
821  }
822  if (Dim >= 3)
823  {
824  int nf;
825  input >> ident >> nf; // shared_faces (in this group)
826  nf += sface_counter;
827  MFEM_VERIFY(nf <= group_sface.Size_of_connections(),
828  "incorrect number of total_shared_faces");
829  group_sface.GetI()[gr] = nf;
830  for ( ; sface_counter < nf; sface_counter++)
831  {
832  group_sface.GetJ()[sface_counter] = sface_counter;
833  Element *sface = ReadElementWithoutAttr(input);
834  shared_faces[sface_counter] = sface;
835  const int *v = sface->GetVertices();
836  switch (sface->GetType())
837  {
838  case Element::TRIANGLE:
839  sface_lface[sface_counter] = (*faces_tbl)(v[0], v[1], v[2]);
840  break;
842  sface_lface[sface_counter] =
843  (*faces_tbl)(v[0], v[1], v[2], v[3]);
844  break;
845  }
846  }
847  }
848  }
849  delete faces_tbl;
850  delete v_to_v;
851 
852  const bool refine = true;
853  const bool fix_orientation = false;
854  Finalize(refine, fix_orientation);
855 
856  // If the mesh has Nodes, convert them from GridFunction to ParGridFunction?
857 
858  // note: attributes and bdr_attributes are local lists
859 
860  // TODO: AMR meshes, NURBS meshes?
861 }
862 
863 ParMesh::ParMesh(ParMesh *orig_mesh, int ref_factor, int ref_type)
864  : Mesh(orig_mesh, ref_factor, ref_type),
865  MyComm(orig_mesh->GetComm()),
866  NRanks(orig_mesh->GetNRanks()),
867  MyRank(orig_mesh->GetMyRank()),
868  gtopo(orig_mesh->gtopo),
869  have_face_nbr_data(false),
870  pncmesh(NULL)
871 {
872  // Need to initialize:
873  // - shared_edges, shared_faces
874  // - group_svert, group_sedge, group_sface
875  // - svert_lvert, sedge_ledge, sface_lface
876 
877  H1_FECollection rfec(ref_factor, Dim, ref_type);
878  ParFiniteElementSpace rfes(orig_mesh, &rfec);
879 
880  // count the number of entries in each row of group_s{vert,edge,face}
881  group_svert.MakeI(GetNGroups()-1); // exclude the local group 0
884  for (int gr = 1; gr < GetNGroups(); gr++)
885  {
886  // orig vertex -> vertex
887  group_svert.AddColumnsInRow(gr-1, orig_mesh->GroupNVertices(gr));
888  // orig edge -> (ref_factor-1) vertices and (ref_factor) edges
889  const int orig_ne = orig_mesh->GroupNEdges(gr);
890  group_svert.AddColumnsInRow(gr-1, (ref_factor-1)*orig_ne);
891  group_sedge.AddColumnsInRow(gr-1, ref_factor*orig_ne);
892  // orig face -> (?) vertices, (?) edges, and (?) faces
893  const int orig_nf = orig_mesh->GroupNFaces(gr);
894  const int *orig_sf = orig_mesh->group_sface.GetRow(gr-1);
895  for (int fi = 0; fi < orig_nf; fi++)
896  {
897  const int orig_l_face = orig_mesh->sface_lface[orig_sf[fi]];
898  const int geom = orig_mesh->GetFaceBaseGeometry(orig_l_face);
899  const int nvert = Geometry::NumVerts[geom];
900  RefinedGeometry &RG =
901  *GlobGeometryRefiner.Refine(geom, ref_factor, ref_factor);
902 
903  // count internal vertices
904  group_svert.AddColumnsInRow(gr-1, rfec.DofForGeometry(geom));
905  // count internal edges
907  // count refined faces
908  group_sface.AddColumnsInRow(gr-1, RG.RefGeoms.Size()/nvert);
909  }
910  }
911 
912  group_svert.MakeJ();
914 
915  group_sedge.MakeJ();
918 
919  group_sface.MakeJ();
922 
923  Array<int> rdofs;
924  for (int gr = 1; gr < GetNGroups(); gr++)
925  {
926  // add shared vertices from original shared vertices
927  const int orig_n_verts = orig_mesh->GroupNVertices(gr);
928  for (int j = 0; j < orig_n_verts; j++)
929  {
930  rfes.GetVertexDofs(orig_mesh->GroupVertex(gr, j), rdofs);
931  group_svert.AddConnection(gr-1, svert_lvert.Append(rdofs[0])-1);
932  }
933 
934  // add refined shared edges; add shared vertices from refined shared edges
935  const int orig_n_edges = orig_mesh->GroupNEdges(gr);
936  const int geom = Geometry::SEGMENT;
937  const int nvert = Geometry::NumVerts[geom];
938  RefinedGeometry &RG = *GlobGeometryRefiner.Refine(geom, ref_factor);
939  for (int e = 0; e < orig_n_edges; e++)
940  {
941  rfes.GetSharedEdgeDofs(gr, e, rdofs);
942  MFEM_ASSERT(rdofs.Size() == RG.RefPts.Size(), "");
943  // add the internal edge 'rdofs' as shared vertices
944  for (int j = 2; j < rdofs.Size(); j++)
945  {
946  group_svert.AddConnection(gr-1, svert_lvert.Append(rdofs[j])-1);
947  }
948  const int *c2h_map = rfec.GetDofMap(geom);
949  for (int j = 0; j < RG.RefGeoms.Size(); j += nvert)
950  {
951  Element *elem = NewElement(geom);
952  int *v = elem->GetVertices();
953  for (int k = 0; k < nvert; k++)
954  {
955  int cid = RG.RefGeoms[j+k]; // local Cartesian index
956  v[k] = rdofs[c2h_map[cid]];
957  }
958  group_sedge.AddConnection(gr-1, shared_edges.Append(elem)-1);
959  }
960  }
961  // add refined shared faces; add shared edges and shared vertices from
962  // refined shared faces
963  const int orig_nf = orig_mesh->group_sface.RowSize(gr-1);
964  const int *orig_sf = orig_mesh->group_sface.GetRow(gr-1);
965  for (int f = 0; f < orig_nf; f++)
966  {
967  const int orig_l_face = orig_mesh->sface_lface[orig_sf[f]];
968  const int geom = orig_mesh->GetFaceBaseGeometry(orig_l_face);
969  const int nvert = Geometry::NumVerts[geom];
970  RefinedGeometry &RG =
971  *GlobGeometryRefiner.Refine(geom, ref_factor, ref_factor);
972 
973  rfes.GetSharedFaceDofs(gr, f, rdofs);
974  MFEM_ASSERT(rdofs.Size() == RG.RefPts.Size(), "");
975  // add the internal face 'rdofs' as shared vertices
976  const int num_int_verts = rfec.DofForGeometry(geom);
977  for (int j = rdofs.Size()-num_int_verts; j < rdofs.Size(); j++)
978  {
979  group_svert.AddConnection(gr-1, svert_lvert.Append(rdofs[j])-1);
980  }
981  const int *c2h_map = rfec.GetDofMap(geom);
982  // add the internal (for the shared face) edges as shared edges
983  for (int j = 2*RG.NumBdrEdges; j < RG.RefEdges.Size(); j += 2)
984  {
986  int *v = elem->GetVertices();
987  for (int k = 0; k < 2; k++)
988  {
989  v[k] = rdofs[c2h_map[RG.RefEdges[j+k]]];
990  }
991  group_sedge.AddConnection(gr-1, shared_edges.Append(elem)-1);
992  }
993  // add refined shared faces
994  for (int j = 0; j < RG.RefGeoms.Size(); j += nvert)
995  {
996  Element *elem = NewElement(geom);
997  int *v = elem->GetVertices();
998  for (int k = 0; k < nvert; k++)
999  {
1000  int cid = RG.RefGeoms[j+k]; // local Cartesian index
1001  v[k] = rdofs[c2h_map[cid]];
1002  }
1003  group_sface.AddConnection(gr-1, shared_faces.Append(elem)-1);
1004  }
1005  }
1006  }
1010 
1011  // determine sedge_ledge
1012  if (shared_edges.Size() > 0)
1013  {
1014  DSTable v_to_v(NumOfVertices);
1015  GetVertexToVertexTable(v_to_v);
1016  for (int se = 0; se < shared_edges.Size(); se++)
1017  {
1018  const int *v = shared_edges[se]->GetVertices();
1019  const int l_edge = v_to_v(v[0], v[1]);
1020  MFEM_ASSERT(l_edge >= 0, "invalid shared edge");
1021  sedge_ledge[se] = l_edge;
1022  }
1023  }
1024 
1025  // determine sface_lface
1026  if (shared_faces.Size() > 0)
1027  {
1028  STable3D *faces_tbl = GetFacesTable();
1029  for (int sf = 0; sf < shared_faces.Size(); sf++)
1030  {
1031  int l_face;
1032  const int *v = shared_faces[sf]->GetVertices();
1033  switch (shared_faces[sf]->GetGeometryType())
1034  {
1035  case Geometry::TRIANGLE:
1036  l_face = (*faces_tbl)(v[0], v[1], v[2]);
1037  break;
1038  case Geometry::SQUARE:
1039  l_face = (*faces_tbl)(v[0], v[1], v[2], v[3]);
1040  break;
1041  default:
1042  MFEM_ABORT("invalid face geometry");
1043  l_face = -1;
1044  }
1045  MFEM_ASSERT(l_face >= 0, "invalid shared face");
1046  sface_lface[sf] = l_face;
1047  }
1048  delete faces_tbl;
1049  }
1050 }
1051 
1052 void ParMesh::GroupEdge(int group, int i, int &edge, int &o)
1053 {
1054  int sedge = group_sedge.GetRow(group-1)[i];
1055  edge = sedge_ledge[sedge];
1056  int *v = shared_edges[sedge]->GetVertices();
1057  o = (v[0] < v[1]) ? (+1) : (-1);
1058 }
1059 
1060 void ParMesh::GroupFace(int group, int i, int &face, int &o)
1061 {
1062  int sface = group_sface.GetRow(group-1)[i];
1063  face = sface_lface[sface];
1064  // face gives the base orientation
1065  if (faces[face]->GetType() == Element::TRIANGLE)
1066  {
1067  o = GetTriOrientation(faces[face]->GetVertices(),
1068  shared_faces[sface]->GetVertices());
1069  }
1070  if (faces[face]->GetType() == Element::QUADRILATERAL)
1071  {
1072  o = GetQuadOrientation(faces[face]->GetVertices(),
1073  shared_faces[sface]->GetVertices());
1074  }
1075 }
1076 
1078 {
1079  Array<int> order;
1080  GetEdgeOrdering(v_to_v, order); // local edge ordering
1081 
1082  // create a GroupCommunicator on the shared edges
1083  GroupCommunicator sedge_comm(gtopo);
1084  {
1085  // initialize sedge_comm
1086  Table &gr_sedge = sedge_comm.GroupLDofTable(); // differs from group_sedge
1087  gr_sedge.SetDims(GetNGroups(), shared_edges.Size());
1088  gr_sedge.GetI()[0] = 0;
1089  for (int gr = 1; gr <= GetNGroups(); gr++)
1090  {
1091  gr_sedge.GetI()[gr] = group_sedge.GetI()[gr-1];
1092  }
1093  for (int k = 0; k < shared_edges.Size(); k++)
1094  {
1095  gr_sedge.GetJ()[k] = group_sedge.GetJ()[k];
1096  }
1097  sedge_comm.Finalize();
1098  }
1099 
1100  Array<int> sedge_ord(shared_edges.Size());
1101  Array<Pair<int,int> > sedge_ord_map(shared_edges.Size());
1102  for (int k = 0; k < shared_edges.Size(); k++)
1103  {
1104  sedge_ord[k] = order[sedge_ledge[group_sedge.GetJ()[k]]];
1105  }
1106 
1107  sedge_comm.Bcast<int>(sedge_ord, 1);
1108 
1109  for (int k = 0, gr = 1; gr < GetNGroups(); gr++)
1110  {
1111  const int n = group_sedge.RowSize(gr-1);
1112  if (n == 0) { continue; }
1113  sedge_ord_map.SetSize(n);
1114  for (int j = 0; j < n; j++)
1115  {
1116  sedge_ord_map[j].one = sedge_ord[k+j];
1117  sedge_ord_map[j].two = j;
1118  }
1119  SortPairs<int, int>(sedge_ord_map, n);
1120  for (int j = 0; j < n; j++)
1121  {
1122  int sedge_from = group_sedge.GetJ()[k+j];
1123  sedge_ord[k+j] = order[sedge_ledge[sedge_from]];
1124  }
1125  std::sort(&sedge_ord[k], &sedge_ord[k] + n);
1126  for (int j = 0; j < n; j++)
1127  {
1128  int sedge_to = group_sedge.GetJ()[k+sedge_ord_map[j].two];
1129  order[sedge_ledge[sedge_to]] = sedge_ord[k+j];
1130  }
1131  k += n;
1132  }
1133 
1134 #ifdef MFEM_DEBUG
1135  {
1136  Array<Pair<int, double> > ilen_len(order.Size());
1137 
1138  for (int i = 0; i < NumOfVertices; i++)
1139  {
1140  for (DSTable::RowIterator it(v_to_v, i); !it; ++it)
1141  {
1142  int j = it.Index();
1143  ilen_len[j].one = order[j];
1144  ilen_len[j].two = GetLength(i, it.Column());
1145  }
1146  }
1147 
1148  SortPairs<int, double>(ilen_len, order.Size());
1149 
1150  double d_max = 0.;
1151  for (int i = 1; i < order.Size(); i++)
1152  {
1153  d_max = std::max(d_max, ilen_len[i-1].two-ilen_len[i].two);
1154  }
1155 
1156 #if 0
1157  // Debug message from every MPI rank.
1158  mfem::out << "proc. " << MyRank << '/' << NRanks << ": d_max = " << d_max
1159  << endl;
1160 #else
1161  // Debug message just from rank 0.
1162  double glob_d_max;
1163  MPI_Reduce(&d_max, &glob_d_max, 1, MPI_DOUBLE, MPI_MAX, 0, MyComm);
1164  if (MyRank == 0)
1165  {
1166  mfem::out << "glob_d_max = " << glob_d_max << endl;
1167  }
1168 #endif
1169  }
1170 #endif
1171 
1172  // use 'order' to mark the tets, the boundary triangles, and the shared
1173  // triangle faces
1174  for (int i = 0; i < NumOfElements; i++)
1175  {
1176  if (elements[i]->GetType() == Element::TETRAHEDRON)
1177  {
1178  elements[i]->MarkEdge(v_to_v, order);
1179  }
1180  }
1181 
1182  for (int i = 0; i < NumOfBdrElements; i++)
1183  {
1184  if (boundary[i]->GetType() == Element::TRIANGLE)
1185  {
1186  boundary[i]->MarkEdge(v_to_v, order);
1187  }
1188  }
1189 
1190  for (int i = 0; i < shared_faces.Size(); i++)
1191  {
1192  if (shared_faces[i]->GetType() == Element::TRIANGLE)
1193  {
1194  shared_faces[i]->MarkEdge(v_to_v, order);
1195  }
1196  }
1197 }
1198 
1199 // For a line segment with vertices v[0] and v[1], return a number with
1200 // the following meaning:
1201 // 0 - the edge was not refined
1202 // 1 - the edge e was refined once by splitting v[0],v[1]
1203 int ParMesh::GetEdgeSplittings(Element *edge, const DSTable &v_to_v,
1204  int *middle)
1205 {
1206  int m, *v = edge->GetVertices();
1207 
1208  if ((m = v_to_v(v[0], v[1])) != -1 && middle[m] != -1)
1209  {
1210  return 1;
1211  }
1212  else
1213  {
1214  return 0;
1215  }
1216 }
1217 
1218 // For a triangular face with (correctly ordered) vertices v[0], v[1], v[2]
1219 // return a number with the following meaning:
1220 // 0 - the face was not refined
1221 // 1 - the face was refined once by splitting v[0],v[1]
1222 // 2 - the face was refined twice by splitting v[0],v[1] and then v[1],v[2]
1223 // 3 - the face was refined twice by splitting v[0],v[1] and then v[0],v[2]
1224 // 4 - the face was refined three times (as in 2+3)
1225 int ParMesh::GetFaceSplittings(Element *face, const DSTable &v_to_v,
1226  int *middle)
1227 {
1228  int m, right = 0;
1229  int number_of_splittings = 0;
1230  int *v = face->GetVertices();
1231 
1232  if ((m = v_to_v(v[0], v[1])) != -1 && middle[m] != -1)
1233  {
1234  number_of_splittings++;
1235  if ((m = v_to_v(v[1], v[2])) != -1 && middle[m] != -1)
1236  {
1237  right = 1;
1238  number_of_splittings++;
1239  }
1240  if ((m = v_to_v(v[2], v[0])) != -1 && middle[m] != -1)
1241  {
1242  number_of_splittings++;
1243  }
1244 
1245  switch (number_of_splittings)
1246  {
1247  case 2:
1248  if (right == 0)
1249  {
1250  number_of_splittings++;
1251  }
1252  break;
1253  case 3:
1254  number_of_splittings++;
1255  break;
1256  }
1257  }
1258 
1259  return number_of_splittings;
1260 }
1261 
1262 void ParMesh::GenerateOffsets(int N, HYPRE_Int loc_sizes[],
1263  Array<HYPRE_Int> *offsets[]) const
1264 {
1265  if (HYPRE_AssumedPartitionCheck())
1266  {
1267  Array<HYPRE_Int> temp(N);
1268  MPI_Scan(loc_sizes, temp.GetData(), N, HYPRE_MPI_INT, MPI_SUM, MyComm);
1269  for (int i = 0; i < N; i++)
1270  {
1271  offsets[i]->SetSize(3);
1272  (*offsets[i])[0] = temp[i] - loc_sizes[i];
1273  (*offsets[i])[1] = temp[i];
1274  }
1275  MPI_Bcast(temp.GetData(), N, HYPRE_MPI_INT, NRanks-1, MyComm);
1276  for (int i = 0; i < N; i++)
1277  {
1278  (*offsets[i])[2] = temp[i];
1279  // check for overflow
1280  MFEM_VERIFY((*offsets[i])[0] >= 0 && (*offsets[i])[1] >= 0,
1281  "overflow in offsets");
1282  }
1283  }
1284  else
1285  {
1286  Array<HYPRE_Int> temp(N*NRanks);
1287  MPI_Allgather(loc_sizes, N, HYPRE_MPI_INT, temp.GetData(), N,
1288  HYPRE_MPI_INT, MyComm);
1289  for (int i = 0; i < N; i++)
1290  {
1291  Array<HYPRE_Int> &offs = *offsets[i];
1292  offs.SetSize(NRanks+1);
1293  offs[0] = 0;
1294  for (int j = 0; j < NRanks; j++)
1295  {
1296  offs[j+1] = offs[j] + temp[i+N*j];
1297  }
1298  // Check for overflow
1299  MFEM_VERIFY(offs[MyRank] >= 0 && offs[MyRank+1] >= 0,
1300  "overflow in offsets");
1301  }
1302  }
1303 }
1304 
1306  int i, IsoparametricTransformation *ElTr)
1307 {
1308  DenseMatrix &pointmat = ElTr->GetPointMat();
1309  Element *elem = face_nbr_elements[i];
1310 
1311  ElTr->Attribute = elem->GetAttribute();
1312  ElTr->ElementNo = NumOfElements + i;
1313 
1314  if (Nodes == NULL)
1315  {
1316  const int nv = elem->GetNVertices();
1317  const int *v = elem->GetVertices();
1318 
1319  pointmat.SetSize(spaceDim, nv);
1320  for (int k = 0; k < spaceDim; k++)
1321  {
1322  for (int j = 0; j < nv; j++)
1323  {
1324  pointmat(k, j) = face_nbr_vertices[v[j]](k);
1325  }
1326  }
1327 
1329  }
1330  else
1331  {
1332  Array<int> vdofs;
1333  ParGridFunction *pNodes = dynamic_cast<ParGridFunction *>(Nodes);
1334  if (pNodes)
1335  {
1336  pNodes->ParFESpace()->GetFaceNbrElementVDofs(i, vdofs);
1337  int n = vdofs.Size()/spaceDim;
1338  pointmat.SetSize(spaceDim, n);
1339  for (int k = 0; k < spaceDim; k++)
1340  {
1341  for (int j = 0; j < n; j++)
1342  {
1343  pointmat(k,j) = (pNodes->FaceNbrData())(vdofs[n*k+j]);
1344  }
1345  }
1346 
1347  ElTr->SetFE(pNodes->ParFESpace()->GetFaceNbrFE(i));
1348  }
1349  else
1350  {
1351  MFEM_ABORT("Nodes are not ParGridFunction!");
1352  }
1353  }
1354  ElTr->FinalizeTransformation();
1355 }
1356 
1358 {
1359  if (!have_face_nbr_data)
1360  {
1361  return;
1362  }
1363 
1364  have_face_nbr_data = false;
1368  for (int i = 0; i < face_nbr_elements.Size(); i++)
1369  {
1371  }
1372  face_nbr_elements.DeleteAll();
1373  face_nbr_vertices.DeleteAll();
1376 }
1377 
1379 {
1380  if (have_face_nbr_data)
1381  {
1382  return;
1383  }
1384 
1385  if (Nonconforming())
1386  {
1387  // with ParNCMesh we can set up face neighbors without communication
1388  pncmesh->GetFaceNeighbors(*this);
1389  have_face_nbr_data = true;
1390 
1392  return;
1393  }
1394 
1395  Table *gr_sface;
1396  int *s2l_face;
1397  if (Dim == 1)
1398  {
1399  gr_sface = &group_svert;
1400  s2l_face = svert_lvert;
1401  }
1402  else if (Dim == 2)
1403  {
1404  gr_sface = &group_sedge;
1405  s2l_face = sedge_ledge;
1406  }
1407  else
1408  {
1409  gr_sface = &group_sface;
1410  s2l_face = sface_lface;
1411  }
1412 
1413  int num_face_nbrs = 0;
1414  for (int g = 1; g < GetNGroups(); g++)
1415  if (gr_sface->RowSize(g-1) > 0)
1416  {
1417  num_face_nbrs++;
1418  }
1419 
1420  face_nbr_group.SetSize(num_face_nbrs);
1421 
1422  if (num_face_nbrs == 0)
1423  {
1424  have_face_nbr_data = true;
1425  return;
1426  }
1427 
1428  {
1429  // sort face-neighbors by processor rank
1430  Array<Pair<int, int> > rank_group(num_face_nbrs);
1431 
1432  for (int g = 1, counter = 0; g < GetNGroups(); g++)
1433  if (gr_sface->RowSize(g-1) > 0)
1434  {
1435 #ifdef MFEM_DEBUG
1436  if (gtopo.GetGroupSize(g) != 2)
1437  mfem_error("ParMesh::ExchangeFaceNbrData() : "
1438  "group size is not 2!");
1439 #endif
1440  const int *nbs = gtopo.GetGroup(g);
1441  int lproc = (nbs[0]) ? nbs[0] : nbs[1];
1442  rank_group[counter].one = gtopo.GetNeighborRank(lproc);
1443  rank_group[counter].two = g;
1444  counter++;
1445  }
1446 
1447  SortPairs<int, int>(rank_group, rank_group.Size());
1448 
1449  for (int fn = 0; fn < num_face_nbrs; fn++)
1450  {
1451  face_nbr_group[fn] = rank_group[fn].two;
1452  }
1453  }
1454 
1455  MPI_Request *requests = new MPI_Request[2*num_face_nbrs];
1456  MPI_Request *send_requests = requests;
1457  MPI_Request *recv_requests = requests + num_face_nbrs;
1458  MPI_Status *statuses = new MPI_Status[num_face_nbrs];
1459 
1460  int *nbr_data = new int[6*num_face_nbrs];
1461  int *nbr_send_data = nbr_data;
1462  int *nbr_recv_data = nbr_data + 3*num_face_nbrs;
1463 
1464  Array<int> el_marker(GetNE());
1465  Array<int> vertex_marker(GetNV());
1466  el_marker = -1;
1467  vertex_marker = -1;
1468 
1469  Table send_face_nbr_elemdata, send_face_nbr_facedata;
1470 
1471  send_face_nbr_elements.MakeI(num_face_nbrs);
1472  send_face_nbr_vertices.MakeI(num_face_nbrs);
1473  send_face_nbr_elemdata.MakeI(num_face_nbrs);
1474  send_face_nbr_facedata.MakeI(num_face_nbrs);
1475  for (int fn = 0; fn < num_face_nbrs; fn++)
1476  {
1477  int nbr_group = face_nbr_group[fn];
1478  int num_sfaces = gr_sface->RowSize(nbr_group-1);
1479  int *sface = gr_sface->GetRow(nbr_group-1);
1480  for (int i = 0; i < num_sfaces; i++)
1481  {
1482  int lface = s2l_face[sface[i]];
1483  int el = faces_info[lface].Elem1No;
1484  if (el_marker[el] != fn)
1485  {
1486  el_marker[el] = fn;
1488 
1489  const int nv = elements[el]->GetNVertices();
1490  const int *v = elements[el]->GetVertices();
1491  for (int j = 0; j < nv; j++)
1492  if (vertex_marker[v[j]] != fn)
1493  {
1494  vertex_marker[v[j]] = fn;
1496  }
1497 
1498  send_face_nbr_elemdata.AddColumnsInRow(fn, nv + 2);
1499  }
1500  }
1501  send_face_nbr_facedata.AddColumnsInRow(fn, 2*num_sfaces);
1502 
1503  nbr_send_data[3*fn ] = send_face_nbr_elements.GetI()[fn];
1504  nbr_send_data[3*fn+1] = send_face_nbr_vertices.GetI()[fn];
1505  nbr_send_data[3*fn+2] = send_face_nbr_elemdata.GetI()[fn];
1506 
1507  int nbr_rank = GetFaceNbrRank(fn);
1508  int tag = 0;
1509 
1510  MPI_Isend(&nbr_send_data[3*fn], 3, MPI_INT, nbr_rank, tag, MyComm,
1511  &send_requests[fn]);
1512  MPI_Irecv(&nbr_recv_data[3*fn], 3, MPI_INT, nbr_rank, tag, MyComm,
1513  &recv_requests[fn]);
1514  }
1517  send_face_nbr_elemdata.MakeJ();
1518  send_face_nbr_facedata.MakeJ();
1519  el_marker = -1;
1520  vertex_marker = -1;
1521  for (int fn = 0; fn < num_face_nbrs; fn++)
1522  {
1523  int nbr_group = face_nbr_group[fn];
1524  int num_sfaces = gr_sface->RowSize(nbr_group-1);
1525  int *sface = gr_sface->GetRow(nbr_group-1);
1526  for (int i = 0; i < num_sfaces; i++)
1527  {
1528  int lface = s2l_face[sface[i]];
1529  int el = faces_info[lface].Elem1No;
1530  if (el_marker[el] != fn)
1531  {
1532  el_marker[el] = fn;
1534 
1535  const int nv = elements[el]->GetNVertices();
1536  const int *v = elements[el]->GetVertices();
1537  for (int j = 0; j < nv; j++)
1538  if (vertex_marker[v[j]] != fn)
1539  {
1540  vertex_marker[v[j]] = fn;
1542  }
1543 
1544  send_face_nbr_elemdata.AddConnection(fn, GetAttribute(el));
1545  send_face_nbr_elemdata.AddConnection(
1546  fn, GetElementBaseGeometry(el));
1547  send_face_nbr_elemdata.AddConnections(fn, v, nv);
1548  }
1549  send_face_nbr_facedata.AddConnection(fn, el);
1550  int info = faces_info[lface].Elem1Inf;
1551  // change the orientation in info to be relative to the shared face
1552  // in 1D and 2D keep the orientation equal to 0
1553  if (Dim == 3)
1554  {
1555  Element *lf = faces[lface];
1556  const int *sf_v = shared_faces[sface[i]]->GetVertices();
1557 
1558  if (lf->GetGeometryType() == Geometry::TRIANGLE)
1559  {
1560  info += GetTriOrientation(sf_v, lf->GetVertices());
1561  }
1562  else
1563  {
1564  info += GetQuadOrientation(sf_v, lf->GetVertices());
1565  }
1566  }
1567  send_face_nbr_facedata.AddConnection(fn, info);
1568  }
1569  }
1572  send_face_nbr_elemdata.ShiftUpI();
1573  send_face_nbr_facedata.ShiftUpI();
1574 
1575  // convert the vertex indices in send_face_nbr_elemdata
1576  // convert the element indices in send_face_nbr_facedata
1577  for (int fn = 0; fn < num_face_nbrs; fn++)
1578  {
1579  int num_elems = send_face_nbr_elements.RowSize(fn);
1580  int *elems = send_face_nbr_elements.GetRow(fn);
1581  int num_verts = send_face_nbr_vertices.RowSize(fn);
1582  int *verts = send_face_nbr_vertices.GetRow(fn);
1583  int *elemdata = send_face_nbr_elemdata.GetRow(fn);
1584  int num_sfaces = send_face_nbr_facedata.RowSize(fn)/2;
1585  int *facedata = send_face_nbr_facedata.GetRow(fn);
1586 
1587  for (int i = 0; i < num_verts; i++)
1588  {
1589  vertex_marker[verts[i]] = i;
1590  }
1591 
1592  for (int el = 0; el < num_elems; el++)
1593  {
1594  const int nv = elements[el]->GetNVertices();
1595  elemdata += 2; // skip the attribute and the geometry type
1596  for (int j = 0; j < nv; j++)
1597  {
1598  elemdata[j] = vertex_marker[elemdata[j]];
1599  }
1600  elemdata += nv;
1601 
1602  el_marker[elems[el]] = el;
1603  }
1604 
1605  for (int i = 0; i < num_sfaces; i++)
1606  {
1607  facedata[2*i] = el_marker[facedata[2*i]];
1608  }
1609  }
1610 
1611  MPI_Waitall(num_face_nbrs, recv_requests, statuses);
1612 
1613  Array<int> recv_face_nbr_facedata;
1614  Table recv_face_nbr_elemdata;
1615 
1616  // fill-in face_nbr_elements_offset, face_nbr_vertices_offset
1617  face_nbr_elements_offset.SetSize(num_face_nbrs + 1);
1618  face_nbr_vertices_offset.SetSize(num_face_nbrs + 1);
1619  recv_face_nbr_elemdata.MakeI(num_face_nbrs);
1620  face_nbr_elements_offset[0] = 0;
1621  face_nbr_vertices_offset[0] = 0;
1622  for (int fn = 0; fn < num_face_nbrs; fn++)
1623  {
1624  face_nbr_elements_offset[fn+1] =
1625  face_nbr_elements_offset[fn] + nbr_recv_data[3*fn];
1626  face_nbr_vertices_offset[fn+1] =
1627  face_nbr_vertices_offset[fn] + nbr_recv_data[3*fn+1];
1628  recv_face_nbr_elemdata.AddColumnsInRow(fn, nbr_recv_data[3*fn+2]);
1629  }
1630  recv_face_nbr_elemdata.MakeJ();
1631 
1632  MPI_Waitall(num_face_nbrs, send_requests, statuses);
1633 
1634  // send and receive the element data
1635  for (int fn = 0; fn < num_face_nbrs; fn++)
1636  {
1637  int nbr_rank = GetFaceNbrRank(fn);
1638  int tag = 0;
1639 
1640  MPI_Isend(send_face_nbr_elemdata.GetRow(fn),
1641  send_face_nbr_elemdata.RowSize(fn),
1642  MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
1643 
1644  MPI_Irecv(recv_face_nbr_elemdata.GetRow(fn),
1645  recv_face_nbr_elemdata.RowSize(fn),
1646  MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
1647  }
1648 
1649  // convert the element data into face_nbr_elements
1650  face_nbr_elements.SetSize(face_nbr_elements_offset[num_face_nbrs]);
1651  while (true)
1652  {
1653  int fn;
1654  MPI_Waitany(num_face_nbrs, recv_requests, &fn, statuses);
1655 
1656  if (fn == MPI_UNDEFINED)
1657  {
1658  break;
1659  }
1660 
1661  int vert_off = face_nbr_vertices_offset[fn];
1662  int elem_off = face_nbr_elements_offset[fn];
1663  int num_elems = face_nbr_elements_offset[fn+1] - elem_off;
1664  int *recv_elemdata = recv_face_nbr_elemdata.GetRow(fn);
1665 
1666  for (int i = 0; i < num_elems; i++)
1667  {
1668  Element *el = NewElement(recv_elemdata[1]);
1669  el->SetAttribute(recv_elemdata[0]);
1670  recv_elemdata += 2;
1671  int nv = el->GetNVertices();
1672  for (int j = 0; j < nv; j++)
1673  {
1674  recv_elemdata[j] += vert_off;
1675  }
1676  el->SetVertices(recv_elemdata);
1677  recv_elemdata += nv;
1678  face_nbr_elements[elem_off++] = el;
1679  }
1680  }
1681 
1682  MPI_Waitall(num_face_nbrs, send_requests, statuses);
1683 
1684  // send and receive the face data
1685  recv_face_nbr_facedata.SetSize(
1686  send_face_nbr_facedata.Size_of_connections());
1687  for (int fn = 0; fn < num_face_nbrs; fn++)
1688  {
1689  int nbr_rank = GetFaceNbrRank(fn);
1690  int tag = 0;
1691 
1692  MPI_Isend(send_face_nbr_facedata.GetRow(fn),
1693  send_face_nbr_facedata.RowSize(fn),
1694  MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
1695 
1696  // the size of the send and receive face data is the same
1697  MPI_Irecv(&recv_face_nbr_facedata[send_face_nbr_facedata.GetI()[fn]],
1698  send_face_nbr_facedata.RowSize(fn),
1699  MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
1700  }
1701 
1702  // transfer the received face data into faces_info
1703  while (true)
1704  {
1705  int fn;
1706  MPI_Waitany(num_face_nbrs, recv_requests, &fn, statuses);
1707 
1708  if (fn == MPI_UNDEFINED)
1709  {
1710  break;
1711  }
1712 
1713  int elem_off = face_nbr_elements_offset[fn];
1714  int nbr_group = face_nbr_group[fn];
1715  int num_sfaces = gr_sface->RowSize(nbr_group-1);
1716  int *sface = gr_sface->GetRow(nbr_group-1);
1717  int *facedata =
1718  &recv_face_nbr_facedata[send_face_nbr_facedata.GetI()[fn]];
1719 
1720  for (int i = 0; i < num_sfaces; i++)
1721  {
1722  int lface = s2l_face[sface[i]];
1723  FaceInfo &face_info = faces_info[lface];
1724  face_info.Elem2No = -1 - (facedata[2*i] + elem_off);
1725  int info = facedata[2*i+1];
1726  // change the orientation in info to be relative to the local face
1727  if (Dim < 3)
1728  {
1729  info++; // orientation 0 --> orientation 1
1730  }
1731  else
1732  {
1733  int nbr_ori = info%64, nbr_v[4];
1734  Element *lf = faces[lface];
1735  const int *sf_v = shared_faces[sface[i]]->GetVertices();
1736 
1737  if (lf->GetGeometryType() == Geometry::TRIANGLE)
1738  {
1739  // apply the nbr_ori to sf_v to get nbr_v
1740  const int *perm = tri_t::Orient[nbr_ori];
1741  for (int j = 0; j < 3; j++)
1742  {
1743  nbr_v[perm[j]] = sf_v[j];
1744  }
1745  // get the orientation of nbr_v w.r.t. the local face
1746  nbr_ori = GetTriOrientation(lf->GetVertices(), nbr_v);
1747  }
1748  else
1749  {
1750  // apply the nbr_ori to sf_v to get nbr_v
1751  const int *perm = quad_t::Orient[nbr_ori];
1752  for (int j = 0; j < 4; j++)
1753  {
1754  nbr_v[perm[j]] = sf_v[j];
1755  }
1756  // get the orientation of nbr_v w.r.t. the local face
1757  nbr_ori = GetQuadOrientation(lf->GetVertices(), nbr_v);
1758  }
1759 
1760  info = 64*(info/64) + nbr_ori;
1761  }
1762  face_info.Elem2Inf = info;
1763  }
1764  }
1765 
1766  MPI_Waitall(num_face_nbrs, send_requests, statuses);
1767 
1768  // allocate the face_nbr_vertices
1769  face_nbr_vertices.SetSize(face_nbr_vertices_offset[num_face_nbrs]);
1770 
1771  delete [] nbr_data;
1772 
1773  delete [] statuses;
1774  delete [] requests;
1775 
1776  have_face_nbr_data = true;
1777 
1779 }
1780 
1782 {
1783  if (!have_face_nbr_data)
1784  {
1785  ExchangeFaceNbrData(); // calls this method at the end
1786  }
1787  else if (Nodes == NULL)
1788  {
1789  if (Nonconforming())
1790  {
1791  // with ParNCMesh we already have the vertices
1792  return;
1793  }
1794 
1795  int num_face_nbrs = GetNFaceNeighbors();
1796 
1797  MPI_Request *requests = new MPI_Request[2*num_face_nbrs];
1798  MPI_Request *send_requests = requests;
1799  MPI_Request *recv_requests = requests + num_face_nbrs;
1800  MPI_Status *statuses = new MPI_Status[num_face_nbrs];
1801 
1802  // allocate buffer and copy the vertices to be sent
1804  for (int i = 0; i < send_vertices.Size(); i++)
1805  {
1806  send_vertices[i] = vertices[send_face_nbr_vertices.GetJ()[i]];
1807  }
1808 
1809  // send and receive the vertices
1810  for (int fn = 0; fn < num_face_nbrs; fn++)
1811  {
1812  int nbr_rank = GetFaceNbrRank(fn);
1813  int tag = 0;
1814 
1815  MPI_Isend(send_vertices[send_face_nbr_vertices.GetI()[fn]](),
1817  MPI_DOUBLE, nbr_rank, tag, MyComm, &send_requests[fn]);
1818 
1820  3*(face_nbr_vertices_offset[fn+1] -
1822  MPI_DOUBLE, nbr_rank, tag, MyComm, &recv_requests[fn]);
1823  }
1824 
1825  MPI_Waitall(num_face_nbrs, recv_requests, statuses);
1826  MPI_Waitall(num_face_nbrs, send_requests, statuses);
1827 
1828  delete [] statuses;
1829  delete [] requests;
1830  }
1831  else
1832  {
1833  ParGridFunction *pNodes = dynamic_cast<ParGridFunction *>(Nodes);
1834  MFEM_VERIFY(pNodes != NULL, "Nodes are not ParGridFunction!");
1835  pNodes->ExchangeFaceNbrData();
1836  }
1837 }
1838 
1839 int ParMesh::GetFaceNbrRank(int fn) const
1840 {
1841  if (Conforming())
1842  {
1843  int nbr_group = face_nbr_group[fn];
1844  const int *nbs = gtopo.GetGroup(nbr_group);
1845  int nbr_lproc = (nbs[0]) ? nbs[0] : nbs[1];
1846  int nbr_rank = gtopo.GetNeighborRank(nbr_lproc);
1847  return nbr_rank;
1848  }
1849  else
1850  {
1851  // NC: simplified handling of face neighbor ranks
1852  return face_nbr_group[fn];
1853  }
1854 }
1855 
1857 {
1858  const Array<int> *s2l_face;
1859  if (Dim == 1)
1860  {
1861  s2l_face = &svert_lvert;
1862  }
1863  else if (Dim == 2)
1864  {
1865  s2l_face = &sedge_ledge;
1866  }
1867  else
1868  {
1869  s2l_face = &sface_lface;
1870  }
1871 
1872  Table *face_elem = new Table;
1873 
1874  face_elem->MakeI(faces_info.Size());
1875 
1876  for (int i = 0; i < faces_info.Size(); i++)
1877  {
1878  if (faces_info[i].Elem2No >= 0)
1879  {
1880  face_elem->AddColumnsInRow(i, 2);
1881  }
1882  else
1883  {
1884  face_elem->AddAColumnInRow(i);
1885  }
1886  }
1887  for (int i = 0; i < s2l_face->Size(); i++)
1888  {
1889  face_elem->AddAColumnInRow((*s2l_face)[i]);
1890  }
1891 
1892  face_elem->MakeJ();
1893 
1894  for (int i = 0; i < faces_info.Size(); i++)
1895  {
1896  face_elem->AddConnection(i, faces_info[i].Elem1No);
1897  if (faces_info[i].Elem2No >= 0)
1898  {
1899  face_elem->AddConnection(i, faces_info[i].Elem2No);
1900  }
1901  }
1902  for (int i = 0; i < s2l_face->Size(); i++)
1903  {
1904  int lface = (*s2l_face)[i];
1905  int nbr_elem_idx = -1 - faces_info[lface].Elem2No;
1906  face_elem->AddConnection(lface, NumOfElements + nbr_elem_idx);
1907  }
1908 
1909  face_elem->ShiftUpI();
1910 
1911  return face_elem;
1912 }
1913 
1915  FaceElementTransformations* FETr, int face_type, int face_geom)
1916 {
1917  // calculate composition of FETr->Loc1 and FETr->Elem1
1919  if (Nodes == NULL)
1920  {
1921  FETr->Elem1->Transform(FETr->Loc1.Transf.GetPointMat(), face_pm);
1923  }
1924  else
1925  {
1926  const FiniteElement* face_el =
1927  Nodes->FESpace()->GetTraceElement(FETr->Elem1No, face_geom);
1928 
1929 #if 0 // TODO: handle the case of non-interpolatory Nodes
1930  DenseMatrix I;
1931  face_el->Project(Transformation.GetFE(), FETr->Loc1.Transf, I);
1932  MultABt(Transformation.GetPointMat(), I, pm_face);
1933 #else
1934  IntegrationRule eir(face_el->GetDof());
1935  FETr->Loc1.Transform(face_el->GetNodes(), eir);
1936  Nodes->GetVectorValues(*FETr->Elem1, eir, face_pm);
1937 #endif
1938  FaceTransformation.SetFE(face_el);
1939  }
1941  return &FaceTransformation;
1942 }
1943 
1945 GetSharedFaceTransformations(int sf, bool fill2)
1946 {
1947  int FaceNo = GetSharedFace(sf);
1948 
1949  FaceInfo &face_info = faces_info[FaceNo];
1950 
1951  bool is_slave = Nonconforming() && IsSlaveFace(face_info);
1952  bool is_ghost = Nonconforming() && FaceNo >= GetNumFaces();
1953 
1954  NCFaceInfo* nc_info = NULL;
1955  if (is_slave) { nc_info = &nc_faces_info[face_info.NCFace]; }
1956 
1957  int local_face = is_ghost ? nc_info->MasterFace : FaceNo;
1958  int face_type = GetFaceElementType(local_face);
1959  int face_geom = GetFaceGeometryType(local_face);
1960 
1961  // setup the transformation for the first element
1962  FaceElemTr.Elem1No = face_info.Elem1No;
1965 
1966  // setup the transformation for the second (neighbor) element
1967  if (fill2)
1968  {
1969  FaceElemTr.Elem2No = -1 - face_info.Elem2No;
1972  }
1973  else
1974  {
1975  FaceElemTr.Elem2No = -1;
1976  }
1977 
1978  // setup the face transformation if the face is not a ghost
1979  FaceElemTr.FaceGeom = face_geom;
1980  if (!is_ghost)
1981  {
1983  // NOTE: The above call overwrites FaceElemTr.Loc1
1984  }
1985 
1986  // setup Loc1 & Loc2
1987  int elem_type = GetElementType(face_info.Elem1No);
1988  GetLocalFaceTransformation(face_type, elem_type, FaceElemTr.Loc1.Transf,
1989  face_info.Elem1Inf);
1990 
1991  if (fill2)
1992  {
1993  elem_type = face_nbr_elements[FaceElemTr.Elem2No]->GetType();
1994  GetLocalFaceTransformation(face_type, elem_type, FaceElemTr.Loc2.Transf,
1995  face_info.Elem2Inf);
1996  }
1997 
1998  // adjust Loc1 or Loc2 of the master face if this is a slave face
1999  if (is_slave)
2000  {
2001  // is a ghost slave? -> master not a ghost -> choose Elem1 local transf
2002  // not a ghost slave? -> master is a ghost -> choose Elem2 local transf
2004  is_ghost ? FaceElemTr.Loc1.Transf : FaceElemTr.Loc2.Transf;
2005 
2006  if (is_ghost || fill2)
2007  {
2008  ApplyLocalSlaveTransformation(loctr, face_info);
2009  }
2010 
2011  if (face_type == Element::SEGMENT && fill2)
2012  {
2013  // fix slave orientation in 2D: flip Loc2 to match Loc1 and Face
2015  std::swap(pm(0,0), pm(0,1));
2016  std::swap(pm(1,0), pm(1,1));
2017  }
2018  }
2019 
2020  // for ghost faces we need a special version of GetFaceTransformation
2021  if (is_ghost)
2022  {
2023  FaceElemTr.Face =
2024  GetGhostFaceTransformation(&FaceElemTr, face_type, face_geom);
2025  }
2026 
2027  return &FaceElemTr;
2028 }
2029 
2031 {
2032  if (Conforming())
2033  {
2034  switch (Dim)
2035  {
2036  case 1: return svert_lvert.Size();
2037  case 2: return sedge_ledge.Size();
2038  default: return sface_lface.Size();
2039  }
2040  }
2041  else
2042  {
2043  MFEM_ASSERT(Dim > 1, "");
2044  const NCMesh::NCList &shared = pncmesh->GetSharedList(Dim-1);
2045  return shared.conforming.size() + shared.slaves.size();
2046  }
2047 }
2048 
2049 int ParMesh::GetSharedFace(int sface) const
2050 {
2051  if (Conforming())
2052  {
2053  switch (Dim)
2054  {
2055  case 1: return svert_lvert[sface];
2056  case 2: return sedge_ledge[sface];
2057  default: return sface_lface[sface];
2058  }
2059  }
2060  else
2061  {
2062  MFEM_ASSERT(Dim > 1, "");
2063  const NCMesh::NCList &shared = pncmesh->GetSharedList(Dim-1);
2064  int csize = (int) shared.conforming.size();
2065  return sface < csize
2066  ? shared.conforming[sface].index
2067  : shared.slaves[sface - csize].index;
2068  }
2069 }
2070 
2072 {
2073  if (Dim != 3 || !(meshgen & 1))
2074  {
2075  return;
2076  }
2077 
2079 
2080  int *v;
2081 
2082  // The local edge and face numbering is changed therefore we need to
2083  // update sedge_ledge and sface_lface.
2084  {
2085  DSTable v_to_v(NumOfVertices);
2086  GetVertexToVertexTable(v_to_v);
2087  for (int i = 0; i < shared_edges.Size(); i++)
2088  {
2089  v = shared_edges[i]->GetVertices();
2090  sedge_ledge[i] = v_to_v(v[0], v[1]);
2091  }
2092  }
2093 
2094  // Rotate shared faces and update sface_lface.
2095  // Note that no communication is needed to ensure that the shared
2096  // faces are rotated in the same way in both processors. This is
2097  // automatic due to various things, e.g. the global to local vertex
2098  // mapping preserves the global order; also the way new vertices
2099  // are introduced during refinement is essential.
2100  {
2101  STable3D *faces_tbl = GetFacesTable();
2102  for (int i = 0; i < shared_faces.Size(); i++)
2103  if (shared_faces[i]->GetType() == Element::TRIANGLE)
2104  {
2105  v = shared_faces[i]->GetVertices();
2106 
2107  Rotate3(v[0], v[1], v[2]);
2108 
2109  sface_lface[i] = (*faces_tbl)(v[0], v[1], v[2]);
2110  }
2111  delete faces_tbl;
2112  }
2113 }
2114 
2115 void ParMesh::LocalRefinement(const Array<int> &marked_el, int type)
2116 {
2117  int i, j;
2118 
2119  if (pncmesh)
2120  {
2121  MFEM_ABORT("Local and nonconforming refinements cannot be mixed.");
2122  }
2123 
2125 
2127 
2128  if (Dim == 3)
2129  {
2130  int uniform_refinement = 0;
2131  if (type < 0)
2132  {
2133  type = -type;
2134  uniform_refinement = 1;
2135  }
2136 
2137  // 1. Get table of vertex to vertex connections.
2138  DSTable v_to_v(NumOfVertices);
2139  GetVertexToVertexTable(v_to_v);
2140 
2141  // 2. Create a marker array for all edges (vertex to vertex connections).
2142  Array<int> middle(v_to_v.NumberOfEntries());
2143  middle = -1;
2144 
2145  // 3. Do the red refinement.
2146  switch (type)
2147  {
2148  case 1:
2149  for (i = 0; i < marked_el.Size(); i++)
2150  {
2151  Bisection(marked_el[i], v_to_v, NULL, NULL, middle);
2152  }
2153  break;
2154  case 2:
2155  for (i = 0; i < marked_el.Size(); i++)
2156  {
2157  Bisection(marked_el[i], v_to_v, NULL, NULL, middle);
2158 
2159  Bisection(NumOfElements - 1, v_to_v, NULL, NULL, middle);
2160  Bisection(marked_el[i], v_to_v, NULL, NULL, middle);
2161  }
2162  break;
2163  case 3:
2164  for (i = 0; i < marked_el.Size(); i++)
2165  {
2166  Bisection(marked_el[i], v_to_v, NULL, NULL, middle);
2167 
2168  j = NumOfElements - 1;
2169  Bisection(j, v_to_v, NULL, NULL, middle);
2170  Bisection(NumOfElements - 1, v_to_v, NULL, NULL, middle);
2171  Bisection(j, v_to_v, NULL, NULL, middle);
2172 
2173  Bisection(marked_el[i], v_to_v, NULL, NULL, middle);
2174  Bisection(NumOfElements-1, v_to_v, NULL, NULL, middle);
2175  Bisection(marked_el[i], v_to_v, NULL, NULL, middle);
2176  }
2177  break;
2178  }
2179 
2180  // 4. Do the green refinement (to get conforming mesh).
2181  int need_refinement;
2182  int refined_edge[5][3] =
2183  {
2184  {0, 0, 0},
2185  {1, 0, 0},
2186  {1, 1, 0},
2187  {1, 0, 1},
2188  {1, 1, 1}
2189  };
2190  int faces_in_group, max_faces_in_group = 0;
2191  // face_splittings identify how the shared faces have been split
2192  int **face_splittings = new int*[GetNGroups()-1];
2193  for (i = 0; i < GetNGroups()-1; i++)
2194  {
2195  faces_in_group = GroupNFaces(i+1);
2196  face_splittings[i] = new int[faces_in_group];
2197  if (faces_in_group > max_faces_in_group)
2198  {
2199  max_faces_in_group = faces_in_group;
2200  }
2201  }
2202  int neighbor, *iBuf = new int[max_faces_in_group];
2203 
2204  Array<int> group_faces;
2205 
2206  MPI_Request request;
2207  MPI_Status status;
2208 
2209 #ifdef MFEM_DEBUG_PARMESH_LOCALREF
2210  int ref_loops_all = 0, ref_loops_par = 0;
2211 #endif
2212  do
2213  {
2214  need_refinement = 0;
2215  for (i = 0; i < NumOfElements; i++)
2216  {
2217  if (elements[i]->NeedRefinement(v_to_v, middle))
2218  {
2219  need_refinement = 1;
2220  Bisection(i, v_to_v, NULL, NULL, middle);
2221  }
2222  }
2223 #ifdef MFEM_DEBUG_PARMESH_LOCALREF
2224  ref_loops_all++;
2225 #endif
2226 
2227  if (uniform_refinement)
2228  {
2229  continue;
2230  }
2231 
2232  // if the mesh is locally conforming start making it globally
2233  // conforming
2234  if (need_refinement == 0)
2235  {
2236 #ifdef MFEM_DEBUG_PARMESH_LOCALREF
2237  ref_loops_par++;
2238 #endif
2239  // MPI_Barrier(MyComm);
2240  const int tag = 293;
2241 
2242  // (a) send the type of interface splitting
2243  for (i = 0; i < GetNGroups()-1; i++)
2244  {
2245  group_sface.GetRow(i, group_faces);
2246  faces_in_group = group_faces.Size();
2247  // it is enough to communicate through the faces
2248  if (faces_in_group == 0) { continue; }
2249 
2250  for (j = 0; j < faces_in_group; j++)
2251  {
2252  face_splittings[i][j] =
2253  GetFaceSplittings(shared_faces[group_faces[j]], v_to_v,
2254  middle);
2255  }
2256  const int *nbs = gtopo.GetGroup(i+1);
2257  neighbor = gtopo.GetNeighborRank(nbs[0] ? nbs[0] : nbs[1]);
2258  MPI_Isend(face_splittings[i], faces_in_group, MPI_INT,
2259  neighbor, tag, MyComm, &request);
2260  }
2261 
2262  // (b) receive the type of interface splitting
2263  for (i = 0; i < GetNGroups()-1; i++)
2264  {
2265  group_sface.GetRow(i, group_faces);
2266  faces_in_group = group_faces.Size();
2267  if (faces_in_group == 0) { continue; }
2268 
2269  const int *nbs = gtopo.GetGroup(i+1);
2270  neighbor = gtopo.GetNeighborRank(nbs[0] ? nbs[0] : nbs[1]);
2271  MPI_Recv(iBuf, faces_in_group, MPI_INT, neighbor,
2272  tag, MyComm, &status);
2273 
2274  for (j = 0; j < faces_in_group; j++)
2275  {
2276  if (iBuf[j] == face_splittings[i][j]) { continue; }
2277 
2278  int *v = shared_faces[group_faces[j]]->GetVertices();
2279  for (int k = 0; k < 3; k++)
2280  {
2281  if (refined_edge[iBuf[j]][k] != 1 ||
2282  refined_edge[face_splittings[i][j]][k] != 0)
2283  { continue; }
2284 
2285  int ind[2] = { v[k], v[(k+1)%3] };
2286  int ii = v_to_v(ind[0], ind[1]);
2287  if (middle[ii] == -1)
2288  {
2289  need_refinement = 1;
2290  middle[ii] = NumOfVertices++;
2291  vertices.Append(Vertex());
2292  AverageVertices(ind, 2, vertices.Size()-1);
2293  }
2294  }
2295  }
2296  }
2297 
2298  i = need_refinement;
2299  MPI_Allreduce(&i, &need_refinement, 1, MPI_INT, MPI_LOR, MyComm);
2300  }
2301  }
2302  while (need_refinement == 1);
2303 
2304 #ifdef MFEM_DEBUG_PARMESH_LOCALREF
2305  i = ref_loops_all;
2306  MPI_Reduce(&i, &ref_loops_all, 1, MPI_INT, MPI_MAX, 0, MyComm);
2307  if (MyRank == 0)
2308  {
2309  mfem::out << "\n\nParMesh::LocalRefinement : max. ref_loops_all = "
2310  << ref_loops_all << ", ref_loops_par = " << ref_loops_par
2311  << '\n' << endl;
2312  }
2313 #endif
2314 
2315  delete [] iBuf;
2316  for (i = 0; i < GetNGroups()-1; i++)
2317  {
2318  delete [] face_splittings[i];
2319  }
2320  delete [] face_splittings;
2321 
2322 
2323  // 5. Update the boundary elements.
2324  do
2325  {
2326  need_refinement = 0;
2327  for (i = 0; i < NumOfBdrElements; i++)
2328  {
2329  if (boundary[i]->NeedRefinement(v_to_v, middle))
2330  {
2331  need_refinement = 1;
2332  Bisection(i, v_to_v, middle);
2333  }
2334  }
2335  }
2336  while (need_refinement == 1);
2337 
2338  if (NumOfBdrElements != boundary.Size())
2339  {
2340  mfem_error("ParMesh::LocalRefinement :"
2341  " (NumOfBdrElements != boundary.Size())");
2342  }
2343 
2344  DeleteLazyTables();
2345 
2346  // 5a. Update the groups after refinement.
2347  if (el_to_face != NULL)
2348  {
2349  RefineGroups(v_to_v, middle);
2350  // GetElementToFaceTable(); // Called by RefineGroups
2351  GenerateFaces();
2352  }
2353 
2354  // 6. Un-mark the Pf elements.
2355  int refinement_edges[2], type, flag;
2356  for (i = 0; i < NumOfElements; i++)
2357  {
2358  Tetrahedron* el = (Tetrahedron*) elements[i];
2359  el->ParseRefinementFlag(refinement_edges, type, flag);
2360 
2361  if (type == Tetrahedron::TYPE_PF)
2362  {
2363  el->CreateRefinementFlag(refinement_edges, Tetrahedron::TYPE_PU,
2364  flag);
2365  }
2366  }
2367 
2368  // 7. Free the allocated memory.
2369  middle.DeleteAll();
2370 
2371  if (el_to_edge != NULL)
2372  {
2374  }
2375  } // 'if (Dim == 3)'
2376 
2377 
2378  if (Dim == 2)
2379  {
2380  int uniform_refinement = 0;
2381  if (type < 0)
2382  {
2383  // type = -type; // not used
2384  uniform_refinement = 1;
2385  }
2386 
2387  // 1. Get table of vertex to vertex connections.
2388  DSTable v_to_v(NumOfVertices);
2389  GetVertexToVertexTable(v_to_v);
2390 
2391  // 2. Get edge to element connections in arrays edge1 and edge2
2392  int nedges = v_to_v.NumberOfEntries();
2393  int *edge1 = new int[nedges];
2394  int *edge2 = new int[nedges];
2395  int *middle = new int[nedges];
2396 
2397  for (i = 0; i < nedges; i++)
2398  {
2399  edge1[i] = edge2[i] = middle[i] = -1;
2400  }
2401 
2402  for (i = 0; i < NumOfElements; i++)
2403  {
2404  int *v = elements[i]->GetVertices();
2405  for (j = 0; j < 3; j++)
2406  {
2407  int ind = v_to_v(v[j], v[(j+1)%3]);
2408  (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
2409  }
2410  }
2411 
2412  // 3. Do the red refinement.
2413  for (i = 0; i < marked_el.Size(); i++)
2414  {
2415  RedRefinement(marked_el[i], v_to_v, edge1, edge2, middle);
2416  }
2417 
2418  // 4. Do the green refinement (to get conforming mesh).
2419  int need_refinement;
2420  int edges_in_group, max_edges_in_group = 0;
2421  // edge_splittings identify how the shared edges have been split
2422  int **edge_splittings = new int*[GetNGroups()-1];
2423  for (i = 0; i < GetNGroups()-1; i++)
2424  {
2425  edges_in_group = GroupNEdges(i+1);
2426  edge_splittings[i] = new int[edges_in_group];
2427  if (edges_in_group > max_edges_in_group)
2428  {
2429  max_edges_in_group = edges_in_group;
2430  }
2431  }
2432  int neighbor, *iBuf = new int[max_edges_in_group];
2433 
2434  Array<int> group_edges;
2435 
2436  MPI_Request request;
2437  MPI_Status status;
2438  Vertex V;
2439  V(2) = 0.0;
2440 
2441 #ifdef MFEM_DEBUG_PARMESH_LOCALREF
2442  int ref_loops_all = 0, ref_loops_par = 0;
2443 #endif
2444  do
2445  {
2446  need_refinement = 0;
2447  for (i = 0; i < nedges; i++)
2448  if (middle[i] != -1 && edge1[i] != -1)
2449  {
2450  need_refinement = 1;
2451  GreenRefinement(edge1[i], v_to_v, edge1, edge2, middle);
2452  }
2453 #ifdef MFEM_DEBUG_PARMESH_LOCALREF
2454  ref_loops_all++;
2455 #endif
2456 
2457  if (uniform_refinement)
2458  {
2459  continue;
2460  }
2461 
2462  // if the mesh is locally conforming start making it globally
2463  // conforming
2464  if (need_refinement == 0)
2465  {
2466 #ifdef MFEM_DEBUG_PARMESH_LOCALREF
2467  ref_loops_par++;
2468 #endif
2469  // MPI_Barrier(MyComm);
2470 
2471  // (a) send the type of interface splitting
2472  for (i = 0; i < GetNGroups()-1; i++)
2473  {
2474  group_sedge.GetRow(i, group_edges);
2475  edges_in_group = group_edges.Size();
2476  // it is enough to communicate through the edges
2477  if (edges_in_group != 0)
2478  {
2479  for (j = 0; j < edges_in_group; j++)
2480  {
2481  edge_splittings[i][j] =
2482  GetEdgeSplittings(shared_edges[group_edges[j]], v_to_v,
2483  middle);
2484  }
2485  const int *nbs = gtopo.GetGroup(i+1);
2486  if (nbs[0] == 0)
2487  {
2488  neighbor = gtopo.GetNeighborRank(nbs[1]);
2489  }
2490  else
2491  {
2492  neighbor = gtopo.GetNeighborRank(nbs[0]);
2493  }
2494  MPI_Isend(edge_splittings[i], edges_in_group, MPI_INT,
2495  neighbor, 0, MyComm, &request);
2496  }
2497  }
2498 
2499  // (b) receive the type of interface splitting
2500  for (i = 0; i < GetNGroups()-1; i++)
2501  {
2502  group_sedge.GetRow(i, group_edges);
2503  edges_in_group = group_edges.Size();
2504  if (edges_in_group != 0)
2505  {
2506  const int *nbs = gtopo.GetGroup(i+1);
2507  if (nbs[0] == 0)
2508  {
2509  neighbor = gtopo.GetNeighborRank(nbs[1]);
2510  }
2511  else
2512  {
2513  neighbor = gtopo.GetNeighborRank(nbs[0]);
2514  }
2515  MPI_Recv(iBuf, edges_in_group, MPI_INT, neighbor,
2516  MPI_ANY_TAG, MyComm, &status);
2517 
2518  for (j = 0; j < edges_in_group; j++)
2519  if (iBuf[j] == 1 && edge_splittings[i][j] == 0)
2520  {
2521  int *v = shared_edges[group_edges[j]]->GetVertices();
2522  int ii = v_to_v(v[0], v[1]);
2523 #ifdef MFEM_DEBUG_PARMESH_LOCALREF
2524  if (middle[ii] != -1)
2525  mfem_error("ParMesh::LocalRefinement (triangles) : "
2526  "Oops!");
2527 #endif
2528  need_refinement = 1;
2529  middle[ii] = NumOfVertices++;
2530  for (int c = 0; c < 2; c++)
2531  {
2532  V(c) = 0.5 * (vertices[v[0]](c) + vertices[v[1]](c));
2533  }
2534  vertices.Append(V);
2535  }
2536  }
2537  }
2538 
2539  i = need_refinement;
2540  MPI_Allreduce(&i, &need_refinement, 1, MPI_INT, MPI_LOR, MyComm);
2541  }
2542  }
2543  while (need_refinement == 1);
2544 
2545 #ifdef MFEM_DEBUG_PARMESH_LOCALREF
2546  i = ref_loops_all;
2547  MPI_Reduce(&i, &ref_loops_all, 1, MPI_INT, MPI_MAX, 0, MyComm);
2548  if (MyRank == 0)
2549  {
2550  mfem::out << "\n\nParMesh::LocalRefinement : max. ref_loops_all = "
2551  << ref_loops_all << ", ref_loops_par = " << ref_loops_par
2552  << '\n' << endl;
2553  }
2554 #endif
2555 
2556  for (i = 0; i < GetNGroups()-1; i++)
2557  {
2558  delete [] edge_splittings[i];
2559  }
2560  delete [] edge_splittings;
2561 
2562  delete [] iBuf;
2563 
2564  // 5. Update the boundary elements.
2565  int v1[2], v2[2], bisect, temp;
2566  temp = NumOfBdrElements;
2567  for (i = 0; i < temp; i++)
2568  {
2569  int *v = boundary[i]->GetVertices();
2570  bisect = v_to_v(v[0], v[1]);
2571  if (middle[bisect] != -1)
2572  {
2573  // the element was refined (needs updating)
2574  if (boundary[i]->GetType() == Element::SEGMENT)
2575  {
2576  v1[0] = v[0]; v1[1] = middle[bisect];
2577  v2[0] = middle[bisect]; v2[1] = v[1];
2578 
2579  boundary[i]->SetVertices(v1);
2580  boundary.Append(new Segment(v2, boundary[i]->GetAttribute()));
2581  }
2582  else
2583  mfem_error("Only bisection of segment is implemented for bdr"
2584  " elem.");
2585  }
2586  }
2587  NumOfBdrElements = boundary.Size();
2588 
2589  DeleteLazyTables();
2590 
2591  // 5a. Update the groups after refinement.
2592  RefineGroups(v_to_v, middle);
2593 
2594  // 6. Free the allocated memory.
2595  delete [] edge1;
2596  delete [] edge2;
2597  delete [] middle;
2598 
2599  if (el_to_edge != NULL)
2600  {
2602  GenerateFaces();
2603  }
2604  } // 'if (Dim == 2)'
2605 
2606  if (Dim == 1) // --------------------------------------------------------
2607  {
2608  int cne = NumOfElements, cnv = NumOfVertices;
2609  NumOfVertices += marked_el.Size();
2610  NumOfElements += marked_el.Size();
2611  vertices.SetSize(NumOfVertices);
2612  elements.SetSize(NumOfElements);
2614 
2615  for (j = 0; j < marked_el.Size(); j++)
2616  {
2617  i = marked_el[j];
2618  Segment *c_seg = (Segment *)elements[i];
2619  int *vert = c_seg->GetVertices(), attr = c_seg->GetAttribute();
2620  int new_v = cnv + j, new_e = cne + j;
2621  AverageVertices(vert, 2, new_v);
2622  elements[new_e] = new Segment(new_v, vert[1], attr);
2623  vert[1] = new_v;
2624 
2625  CoarseFineTr.embeddings[i] = Embedding(i, 1);
2626  CoarseFineTr.embeddings[new_e] = Embedding(i, 2);
2627  }
2628 
2629  static double seg_children[3*2] = { 0.0,1.0, 0.0,0.5, 0.5,1.0 };
2630  CoarseFineTr.point_matrices.UseExternalData(seg_children, 1, 2, 3);
2631 
2632  GenerateFaces();
2633  } // end of 'if (Dim == 1)'
2634 
2636  sequence++;
2637 
2638  UpdateNodes();
2639 
2640 #ifdef MFEM_DEBUG
2641  CheckElementOrientation(false);
2643 #endif
2644 }
2645 
2647  int nc_limit)
2648 {
2649  if (NURBSext)
2650  {
2651  MFEM_ABORT("ParMesh::NonconformingRefinement: NURBS meshes are not "
2652  "supported. Project the NURBS to Nodes first.");
2653  }
2654 
2655  if (!pncmesh)
2656  {
2657  MFEM_ABORT("Can't convert conforming ParMesh to nonconforming ParMesh "
2658  "(you need to initialize the ParMesh from a nonconforming "
2659  "serial Mesh)");
2660  }
2661 
2662  // NOTE: no check of !refinements.Size(), in parallel we would have to reduce
2663 
2664  // do the refinements
2666  pncmesh->Refine(refinements);
2667 
2668  if (nc_limit > 0)
2669  {
2670  pncmesh->LimitNCLevel(nc_limit);
2671  }
2672 
2673  // create a second mesh containing the finest elements from 'pncmesh'
2674  ParMesh* pmesh2 = new ParMesh(*pncmesh);
2675  pncmesh->OnMeshUpdated(pmesh2);
2676 
2677  attributes.Copy(pmesh2->attributes);
2679 
2680  // now swap the meshes, the second mesh will become the old coarse mesh
2681  // and this mesh will be the new fine mesh
2682  Swap(*pmesh2, false);
2683 
2684  delete pmesh2; // NOTE: old face neighbors destroyed here
2685 
2687 
2689  sequence++;
2690 
2691  if (Nodes) // update/interpolate curved mesh
2692  {
2693  Nodes->FESpace()->Update();
2694  Nodes->Update();
2695  }
2696 }
2697 
2699  double threshold, int nc_limit, int op)
2700 {
2701  const Table &dt = pncmesh->GetDerefinementTable();
2702 
2703  pncmesh->SynchronizeDerefinementData(elem_error, dt);
2704 
2705  Array<int> level_ok;
2706  if (nc_limit > 0)
2707  {
2708  pncmesh->CheckDerefinementNCLevel(dt, level_ok, nc_limit);
2709  }
2710 
2711  Array<int> derefs;
2712  for (int i = 0; i < dt.Size(); i++)
2713  {
2714  if (nc_limit > 0 && !level_ok[i]) { continue; }
2715 
2716  const int* fine = dt.GetRow(i);
2717  int size = dt.RowSize(i);
2718 
2719  double error = 0.0;
2720  for (int j = 0; j < size; j++)
2721  {
2722  MFEM_VERIFY(fine[j] < elem_error.Size(), "");
2723 
2724  double err_fine = elem_error[fine[j]];
2725  switch (op)
2726  {
2727  case 0: error = std::min(error, err_fine); break;
2728  case 1: error += err_fine; break;
2729  case 2: error = std::max(error, err_fine); break;
2730  }
2731  }
2732 
2733  if (error < threshold) { derefs.Append(i); }
2734  }
2735 
2736  long glob_size = ReduceInt(derefs.Size());
2737  if (glob_size)
2738  {
2739  DerefineMesh(derefs);
2740  return true;
2741  }
2742 
2743  return false;
2744 }
2745 
2747 {
2748  if (Conforming())
2749  {
2750  MFEM_ABORT("Load balancing is currently not supported for conforming"
2751  " meshes.");
2752  }
2753 
2755 
2756  pncmesh->Rebalance();
2757 
2758  ParMesh* pmesh2 = new ParMesh(*pncmesh);
2759  pncmesh->OnMeshUpdated(pmesh2);
2760 
2761  attributes.Copy(pmesh2->attributes);
2763 
2764  Swap(*pmesh2, false);
2765  delete pmesh2;
2766 
2768 
2770  sequence++;
2771 
2772  if (Nodes) // redistribute curved mesh
2773  {
2774  Nodes->FESpace()->Update();
2775  Nodes->Update();
2776  }
2777 }
2778 
2779 void ParMesh::RefineGroups(const DSTable &v_to_v, int *middle)
2780 {
2781  int i, attr, newv[3], ind, f_ind, *v;
2782 
2783  int group;
2784  Array<int> group_verts, group_edges, group_faces;
2785 
2786  // To update the groups after a refinement, we observe that:
2787  // - every (new and old) vertex, edge and face belongs to exactly one group
2788  // - the refinement does not create new groups
2789  // - a new vertex appears only as the middle of a refined edge
2790  // - a face can be refined 2, 3 or 4 times producing new edges and faces
2791 
2792  int *I_group_svert, *J_group_svert;
2793  int *I_group_sedge, *J_group_sedge;
2794  int *I_group_sface, *J_group_sface;
2795 
2796  I_group_svert = new int[GetNGroups()+1];
2797  I_group_sedge = new int[GetNGroups()+1];
2798  if (Dim == 3)
2799  {
2800  I_group_sface = new int[GetNGroups()+1];
2801  }
2802  else
2803  {
2804  I_group_sface = NULL;
2805  }
2806 
2807  I_group_svert[0] = I_group_svert[1] = 0;
2808  I_group_sedge[0] = I_group_sedge[1] = 0;
2809  if (Dim == 3)
2810  {
2811  I_group_sface[0] = I_group_sface[1] = 0;
2812  }
2813 
2814  // overestimate the size of the J arrays
2815  if (Dim == 3)
2816  {
2817  J_group_svert = new int[group_svert.Size_of_connections()
2819  J_group_sedge = new int[2*group_sedge.Size_of_connections()
2821  J_group_sface = new int[4*group_sface.Size_of_connections()];
2822  }
2823  else if (Dim == 2)
2824  {
2825  J_group_svert = new int[group_svert.Size_of_connections()
2827  J_group_sedge = new int[2*group_sedge.Size_of_connections()];
2828  J_group_sface = NULL;
2829  }
2830  else
2831  {
2832  J_group_svert = J_group_sedge = J_group_sface = NULL;
2833  }
2834 
2835  for (group = 0; group < GetNGroups()-1; group++)
2836  {
2837  // Get the group shared objects
2838  group_svert.GetRow(group, group_verts);
2839  group_sedge.GetRow(group, group_edges);
2840  group_sface.GetRow(group, group_faces);
2841 
2842  // Check which edges have been refined
2843  for (i = 0; i < group_sedge.RowSize(group); i++)
2844  {
2845  v = shared_edges[group_edges[i]]->GetVertices();
2846  ind = middle[v_to_v(v[0], v[1])];
2847  if (ind != -1)
2848  {
2849  // add a vertex
2850  group_verts.Append(svert_lvert.Append(ind)-1);
2851  // update the edges
2852  attr = shared_edges[group_edges[i]]->GetAttribute();
2853  shared_edges.Append(new Segment(v[1], ind, attr));
2854  group_edges.Append(sedge_ledge.Append(-1)-1);
2855  v[1] = ind;
2856  }
2857  }
2858 
2859  // Check which faces have been refined
2860  for (i = 0; i < group_sface.RowSize(group); i++)
2861  {
2862  v = shared_faces[group_faces[i]]->GetVertices();
2863  ind = middle[v_to_v(v[0], v[1])];
2864  if (ind != -1)
2865  {
2866  attr = shared_faces[group_faces[i]]->GetAttribute();
2867  // add the refinement edge
2868  shared_edges.Append(new Segment(v[2], ind, attr));
2869  group_edges.Append(sedge_ledge.Append(-1)-1);
2870  // add a face
2871  f_ind = group_faces.Size();
2872  shared_faces.Append(new Triangle(v[1], v[2], ind, attr));
2873  group_faces.Append(sface_lface.Append(-1)-1);
2874  newv[0] = v[2]; newv[1] = v[0]; newv[2] = ind;
2875  shared_faces[group_faces[i]]->SetVertices(newv);
2876 
2877  // check if the left face has also been refined
2878  // v = shared_faces[group_faces[i]]->GetVertices();
2879  ind = middle[v_to_v(v[0], v[1])];
2880  if (ind != -1)
2881  {
2882  // add the refinement edge
2883  shared_edges.Append(new Segment(v[2], ind, attr));
2884  group_edges.Append(sedge_ledge.Append(-1)-1);
2885  // add a face
2886  shared_faces.Append(new Triangle(v[1], v[2], ind, attr));
2887  group_faces.Append(sface_lface.Append(-1)-1);
2888  newv[0] = v[2]; newv[1] = v[0]; newv[2] = ind;
2889  shared_faces[group_faces[i]]->SetVertices(newv);
2890  }
2891 
2892  // check if the right face has also been refined
2893  v = shared_faces[group_faces[f_ind]]->GetVertices();
2894  ind = middle[v_to_v(v[0], v[1])];
2895  if (ind != -1)
2896  {
2897  // add the refinement edge
2898  shared_edges.Append(new Segment(v[2], ind, attr));
2899  group_edges.Append(sedge_ledge.Append(-1)-1);
2900  // add a face
2901  shared_faces.Append(new Triangle(v[1], v[2], ind, attr));
2902  group_faces.Append(sface_lface.Append(-1)-1);
2903  newv[0] = v[2]; newv[1] = v[0]; newv[2] = ind;
2904  shared_faces[group_faces[f_ind]]->SetVertices(newv);
2905  }
2906  }
2907  }
2908 
2909  I_group_svert[group+1] = I_group_svert[group] + group_verts.Size();
2910  I_group_sedge[group+1] = I_group_sedge[group] + group_edges.Size();
2911  if (Dim == 3)
2912  {
2913  I_group_sface[group+1] = I_group_sface[group] + group_faces.Size();
2914  }
2915 
2916  int *J;
2917  J = J_group_svert+I_group_svert[group];
2918  for (i = 0; i < group_verts.Size(); i++)
2919  {
2920  J[i] = group_verts[i];
2921  }
2922  J = J_group_sedge+I_group_sedge[group];
2923  for (i = 0; i < group_edges.Size(); i++)
2924  {
2925  J[i] = group_edges[i];
2926  }
2927  if (Dim == 3)
2928  {
2929  J = J_group_sface+I_group_sface[group];
2930  for (i = 0; i < group_faces.Size(); i++)
2931  {
2932  J[i] = group_faces[i];
2933  }
2934  }
2935  }
2936 
2937  // Fix the local numbers of shared edges and faces
2938  {
2939  DSTable new_v_to_v(NumOfVertices);
2940  GetVertexToVertexTable(new_v_to_v);
2941  for (i = 0; i < shared_edges.Size(); i++)
2942  {
2943  v = shared_edges[i]->GetVertices();
2944  sedge_ledge[i] = new_v_to_v(v[0], v[1]);
2945  }
2946  }
2947  if (Dim == 3)
2948  {
2949  STable3D *faces_tbl = GetElementToFaceTable(1);
2950  for (i = 0; i < shared_faces.Size(); i++)
2951  {
2952  v = shared_faces[i]->GetVertices();
2953  sface_lface[i] = (*faces_tbl)(v[0], v[1], v[2]);
2954  }
2955  delete faces_tbl;
2956  }
2957 
2958  group_svert.SetIJ(I_group_svert, J_group_svert);
2959  group_sedge.SetIJ(I_group_sedge, J_group_sedge);
2960  if (Dim == 3)
2961  {
2962  group_sface.SetIJ(I_group_sface, J_group_sface);
2963  }
2964 }
2965 
2967 {
2969 
2970  int oedge = NumOfVertices;
2971 
2972  // call Mesh::QuadUniformRefinement so that it won't update the nodes
2973  {
2974  GridFunction *nodes = Nodes;
2975  Nodes = NULL;
2977  Nodes = nodes;
2978  }
2979 
2980  // update the groups
2981  {
2982  int i, attr, ind, *v;
2983 
2984  int group;
2985  Array<int> sverts, sedges;
2986 
2987  int *I_group_svert, *J_group_svert;
2988  int *I_group_sedge, *J_group_sedge;
2989 
2990  I_group_svert = new int[GetNGroups()+1];
2991  I_group_sedge = new int[GetNGroups()+1];
2992 
2993  I_group_svert[0] = I_group_svert[1] = 0;
2994  I_group_sedge[0] = I_group_sedge[1] = 0;
2995 
2996  // compute the size of the J arrays
2997  J_group_svert = new int[group_svert.Size_of_connections()
2999  J_group_sedge = new int[2*group_sedge.Size_of_connections()];
3000 
3001  for (group = 0; group < GetNGroups()-1; group++)
3002  {
3003  // Get the group shared objects
3004  group_svert.GetRow(group, sverts);
3005  group_sedge.GetRow(group, sedges);
3006 
3007  // Process all the edges
3008  for (i = 0; i < group_sedge.RowSize(group); i++)
3009  {
3010  v = shared_edges[sedges[i]]->GetVertices();
3011  ind = oedge + sedge_ledge[sedges[i]];
3012  // add a vertex
3013  sverts.Append(svert_lvert.Append(ind)-1);
3014  // update the edges
3015  attr = shared_edges[sedges[i]]->GetAttribute();
3016  shared_edges.Append(new Segment(v[1], ind, attr));
3017  sedges.Append(sedge_ledge.Append(-1)-1);
3018  v[1] = ind;
3019  }
3020 
3021  I_group_svert[group+1] = I_group_svert[group] + sverts.Size();
3022  I_group_sedge[group+1] = I_group_sedge[group] + sedges.Size();
3023 
3024  int *J;
3025  J = J_group_svert+I_group_svert[group];
3026  for (i = 0; i < sverts.Size(); i++)
3027  {
3028  J[i] = sverts[i];
3029  }
3030  J = J_group_sedge+I_group_sedge[group];
3031  for (i = 0; i < sedges.Size(); i++)
3032  {
3033  J[i] = sedges[i];
3034  }
3035  }
3036 
3037  // Fix the local numbers of shared edges
3038  DSTable v_to_v(NumOfVertices);
3039  GetVertexToVertexTable(v_to_v);
3040  for (i = 0; i < shared_edges.Size(); i++)
3041  {
3042  v = shared_edges[i]->GetVertices();
3043  sedge_ledge[i] = v_to_v(v[0], v[1]);
3044  }
3045 
3046  group_svert.SetIJ(I_group_svert, J_group_svert);
3047  group_sedge.SetIJ(I_group_sedge, J_group_sedge);
3048  }
3049 
3050  UpdateNodes();
3051 }
3052 
3054 {
3056 
3057  int oedge = NumOfVertices;
3058  int oface = oedge + NumOfEdges;
3059 
3060  DSTable v_to_v(NumOfVertices);
3061  GetVertexToVertexTable(v_to_v);
3062  STable3D *faces_tbl = GetFacesTable();
3063 
3064  // call Mesh::HexUniformRefinement so that it won't update the nodes
3065  {
3066  GridFunction *nodes = Nodes;
3067  Nodes = NULL;
3069  Nodes = nodes;
3070  }
3071 
3072  // update the groups
3073  {
3074  int i, attr, newv[4], ind, m[5];
3075  Array<int> v;
3076 
3077  int group;
3078  Array<int> group_verts, group_edges, group_faces;
3079 
3080  int *I_group_svert, *J_group_svert;
3081  int *I_group_sedge, *J_group_sedge;
3082  int *I_group_sface, *J_group_sface;
3083 
3084 #if 0
3085  I_group_svert = new int[GetNGroups()+1];
3086  I_group_sedge = new int[GetNGroups()+1];
3087  I_group_sface = new int[GetNGroups()+1];
3088 
3089  I_group_svert[0] = I_group_svert[1] = 0;
3090  I_group_sedge[0] = I_group_sedge[1] = 0;
3091  I_group_sface[0] = I_group_sface[1] = 0;
3092 #else
3093  I_group_svert = new int[GetNGroups()];
3094  I_group_sedge = new int[GetNGroups()];
3095  I_group_sface = new int[GetNGroups()];
3096 
3097  I_group_svert[0] = 0;
3098  I_group_sedge[0] = 0;
3099  I_group_sface[0] = 0;
3100 #endif
3101 
3102  // compute the size of the J arrays
3103  J_group_svert = new int[group_svert.Size_of_connections()
3106  J_group_sedge = new int[2*group_sedge.Size_of_connections()
3108  J_group_sface = new int[4*group_sface.Size_of_connections()];
3109 
3110  for (group = 0; group < GetNGroups()-1; group++)
3111  {
3112  // Get the group shared objects
3113  group_svert.GetRow(group, group_verts);
3114  group_sedge.GetRow(group, group_edges);
3115  group_sface.GetRow(group, group_faces);
3116 
3117  // Process the edges that have been refined
3118  for (i = 0; i < group_sedge.RowSize(group); i++)
3119  {
3120  shared_edges[group_edges[i]]->GetVertices(v);
3121  ind = oedge + v_to_v(v[0], v[1]);
3122  // add a vertex
3123  group_verts.Append(svert_lvert.Append(ind)-1);
3124  // update the edges
3125  attr = shared_edges[group_edges[i]]->GetAttribute();
3126  shared_edges.Append(new Segment(v[1], ind, attr));
3127  group_edges.Append(sedge_ledge.Append(-1)-1);
3128  newv[0] = v[0]; newv[1] = ind;
3129  shared_edges[group_edges[i]]->SetVertices(newv);
3130  }
3131 
3132  // Process the faces that have been refined
3133  for (i = 0; i < group_sface.RowSize(group); i++)
3134  {
3135  shared_faces[group_faces[i]]->GetVertices(v);
3136  m[0] = oface+(*faces_tbl)(v[0], v[1], v[2], v[3]);
3137  // add a vertex
3138  group_verts.Append(svert_lvert.Append(m[0])-1);
3139  // add the refinement edges
3140  attr = shared_faces[group_faces[i]]->GetAttribute();
3141  m[1] = oedge + v_to_v(v[0], v[1]);
3142  m[2] = oedge + v_to_v(v[1], v[2]);
3143  m[3] = oedge + v_to_v(v[2], v[3]);
3144  m[4] = oedge + v_to_v(v[3], v[0]);
3145  shared_edges.Append(new Segment(m[1], m[0], attr));
3146  group_edges.Append(sedge_ledge.Append(-1)-1);
3147  shared_edges.Append(new Segment(m[2], m[0], attr));
3148  group_edges.Append(sedge_ledge.Append(-1)-1);
3149  shared_edges.Append(new Segment(m[3], m[0], attr));
3150  group_edges.Append(sedge_ledge.Append(-1)-1);
3151  shared_edges.Append(new Segment(m[4], m[0], attr));
3152  group_edges.Append(sedge_ledge.Append(-1)-1);
3153  // update faces
3154  newv[0] = v[0]; newv[1] = m[1]; newv[2] = m[0]; newv[3] = m[4];
3155  shared_faces[group_faces[i]]->SetVertices(newv);
3156  shared_faces.Append(new Quadrilateral(m[1],v[1],m[2],m[0],attr));
3157  group_faces.Append(sface_lface.Append(-1)-1);
3158  shared_faces.Append(new Quadrilateral(m[0],m[2],v[2],m[3],attr));
3159  group_faces.Append(sface_lface.Append(-1)-1);
3160  shared_faces.Append(new Quadrilateral(m[4],m[0],m[3],v[3],attr));
3161  group_faces.Append(sface_lface.Append(-1)-1);
3162  }
3163 
3164  I_group_svert[group+1] = I_group_svert[group] + group_verts.Size();
3165  I_group_sedge[group+1] = I_group_sedge[group] + group_edges.Size();
3166  I_group_sface[group+1] = I_group_sface[group] + group_faces.Size();
3167 
3168  int *J;
3169  J = J_group_svert+I_group_svert[group];
3170  for (i = 0; i < group_verts.Size(); i++)
3171  {
3172  J[i] = group_verts[i];
3173  }
3174  J = J_group_sedge+I_group_sedge[group];
3175  for (i = 0; i < group_edges.Size(); i++)
3176  {
3177  J[i] = group_edges[i];
3178  }
3179  J = J_group_sface+I_group_sface[group];
3180  for (i = 0; i < group_faces.Size(); i++)
3181  {
3182  J[i] = group_faces[i];
3183  }
3184  }
3185 
3186  // Fix the local numbers of shared edges and faces
3187  DSTable new_v_to_v(NumOfVertices);
3188  GetVertexToVertexTable(new_v_to_v);
3189  for (i = 0; i < shared_edges.Size(); i++)
3190  {
3191  shared_edges[i]->GetVertices(v);
3192  sedge_ledge[i] = new_v_to_v(v[0], v[1]);
3193  }
3194 
3195  delete faces_tbl;
3196  faces_tbl = GetFacesTable();
3197  for (i = 0; i < shared_faces.Size(); i++)
3198  {
3199  shared_faces[i]->GetVertices(v);
3200  sface_lface[i] = (*faces_tbl)(v[0], v[1], v[2], v[3]);
3201  }
3202  delete faces_tbl;
3203 
3204  group_svert.SetIJ(I_group_svert, J_group_svert);
3205  group_sedge.SetIJ(I_group_sedge, J_group_sedge);
3206  group_sface.SetIJ(I_group_sface, J_group_sface);
3207  }
3208 
3209  UpdateNodes();
3210 }
3211 
3213 {
3214  if (MyRank == 0)
3215  {
3216  mfem::out << "\nParMesh::NURBSUniformRefinement : Not supported yet!\n";
3217  }
3218 }
3219 
3220 void ParMesh::PrintXG(std::ostream &out) const
3221 {
3222  MFEM_ASSERT(Dim == spaceDim, "2D manifolds not supported");
3223  if (Dim == 3 && meshgen == 1)
3224  {
3225  int i, j, nv;
3226  const int *ind;
3227 
3228  out << "NETGEN_Neutral_Format\n";
3229  // print the vertices
3230  out << NumOfVertices << '\n';
3231  for (i = 0; i < NumOfVertices; i++)
3232  {
3233  for (j = 0; j < Dim; j++)
3234  {
3235  out << " " << vertices[i](j);
3236  }
3237  out << '\n';
3238  }
3239 
3240  // print the elements
3241  out << NumOfElements << '\n';
3242  for (i = 0; i < NumOfElements; i++)
3243  {
3244  nv = elements[i]->GetNVertices();
3245  ind = elements[i]->GetVertices();
3246  out << elements[i]->GetAttribute();
3247  for (j = 0; j < nv; j++)
3248  {
3249  out << " " << ind[j]+1;
3250  }
3251  out << '\n';
3252  }
3253 
3254  // print the boundary + shared faces information
3255  out << NumOfBdrElements + shared_faces.Size() << '\n';
3256  // boundary
3257  for (i = 0; i < NumOfBdrElements; i++)
3258  {
3259  nv = boundary[i]->GetNVertices();
3260  ind = boundary[i]->GetVertices();
3261  out << boundary[i]->GetAttribute();
3262  for (j = 0; j < nv; j++)
3263  {
3264  out << " " << ind[j]+1;
3265  }
3266  out << '\n';
3267  }
3268  // shared faces
3269  for (i = 0; i < shared_faces.Size(); i++)
3270  {
3271  nv = shared_faces[i]->GetNVertices();
3272  ind = shared_faces[i]->GetVertices();
3273  out << shared_faces[i]->GetAttribute();
3274  for (j = 0; j < nv; j++)
3275  {
3276  out << " " << ind[j]+1;
3277  }
3278  out << '\n';
3279  }
3280  }
3281 
3282  if (Dim == 3 && meshgen == 2)
3283  {
3284  int i, j, nv;
3285  const int *ind;
3286 
3287  out << "TrueGrid\n"
3288  << "1 " << NumOfVertices << " " << NumOfElements << " 0 0 0 0 0 0 0\n"
3289  << "0 0 0 1 0 0 0 0 0 0 0\n"
3290  << "0 0 " << NumOfBdrElements+shared_faces.Size()
3291  << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
3292  << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
3293  << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
3294 
3295  // print the vertices
3296  for (i = 0; i < NumOfVertices; i++)
3297  out << i+1 << " 0.0 " << vertices[i](0) << " " << vertices[i](1)
3298  << " " << vertices[i](2) << " 0.0\n";
3299 
3300  // print the elements
3301  for (i = 0; i < NumOfElements; i++)
3302  {
3303  nv = elements[i]->GetNVertices();
3304  ind = elements[i]->GetVertices();
3305  out << i+1 << " " << elements[i]->GetAttribute();
3306  for (j = 0; j < nv; j++)
3307  {
3308  out << " " << ind[j]+1;
3309  }
3310  out << '\n';
3311  }
3312 
3313  // print the boundary information
3314  for (i = 0; i < NumOfBdrElements; i++)
3315  {
3316  nv = boundary[i]->GetNVertices();
3317  ind = boundary[i]->GetVertices();
3318  out << boundary[i]->GetAttribute();
3319  for (j = 0; j < nv; j++)
3320  {
3321  out << " " << ind[j]+1;
3322  }
3323  out << " 1.0 1.0 1.0 1.0\n";
3324  }
3325 
3326  // print the shared faces information
3327  for (i = 0; i < shared_faces.Size(); i++)
3328  {
3329  nv = shared_faces[i]->GetNVertices();
3330  ind = shared_faces[i]->GetVertices();
3331  out << shared_faces[i]->GetAttribute();
3332  for (j = 0; j < nv; j++)
3333  {
3334  out << " " << ind[j]+1;
3335  }
3336  out << " 1.0 1.0 1.0 1.0\n";
3337  }
3338  }
3339 
3340  if (Dim == 2)
3341  {
3342  int i, j, attr;
3343  Array<int> v;
3344 
3345  out << "areamesh2\n\n";
3346 
3347  // print the boundary + shared edges information
3348  out << NumOfBdrElements + shared_edges.Size() << '\n';
3349  // boundary
3350  for (i = 0; i < NumOfBdrElements; i++)
3351  {
3352  attr = boundary[i]->GetAttribute();
3353  boundary[i]->GetVertices(v);
3354  out << attr << " ";
3355  for (j = 0; j < v.Size(); j++)
3356  {
3357  out << v[j] + 1 << " ";
3358  }
3359  out << '\n';
3360  }
3361  // shared edges
3362  for (i = 0; i < shared_edges.Size(); i++)
3363  {
3364  attr = shared_edges[i]->GetAttribute();
3365  shared_edges[i]->GetVertices(v);
3366  out << attr << " ";
3367  for (j = 0; j < v.Size(); j++)
3368  {
3369  out << v[j] + 1 << " ";
3370  }
3371  out << '\n';
3372  }
3373 
3374  // print the elements
3375  out << NumOfElements << '\n';
3376  for (i = 0; i < NumOfElements; i++)
3377  {
3378  attr = elements[i]->GetAttribute();
3379  elements[i]->GetVertices(v);
3380 
3381  out << attr << " ";
3382  if ((j = GetElementType(i)) == Element::TRIANGLE)
3383  {
3384  out << 3 << " ";
3385  }
3386  else if (j == Element::QUADRILATERAL)
3387  {
3388  out << 4 << " ";
3389  }
3390  else if (j == Element::SEGMENT)
3391  {
3392  out << 2 << " ";
3393  }
3394  for (j = 0; j < v.Size(); j++)
3395  {
3396  out << v[j] + 1 << " ";
3397  }
3398  out << '\n';
3399  }
3400 
3401  // print the vertices
3402  out << NumOfVertices << '\n';
3403  for (i = 0; i < NumOfVertices; i++)
3404  {
3405  for (j = 0; j < Dim; j++)
3406  {
3407  out << vertices[i](j) << " ";
3408  }
3409  out << '\n';
3410  }
3411  }
3412  out.flush();
3413 }
3414 
3416 {
3417  // In 2D, this is a workaround for a CPU boundary rendering artifact. We need
3418  // to skip a shared master edge if one of its slaves has the same rank.
3419 
3420  const NCMesh::NCList &list = pncmesh->GetEdgeList();
3421  for (int i = master.slaves_begin; i < master.slaves_end; i++)
3422  {
3423  if (!pncmesh->IsGhost(1, list.slaves[i].index)) { return true; }
3424  }
3425  return false;
3426 }
3427 
3428 void ParMesh::Print(std::ostream &out) const
3429 {
3430  bool print_shared = true;
3431  int i, j, shared_bdr_attr;
3432  Array<int> nc_shared_faces;
3433 
3434  if (NURBSext)
3435  {
3436  Printer(out); // does not print shared boundary
3437  return;
3438  }
3439 
3440  const Array<int>* s2l_face;
3441  if (!pncmesh)
3442  {
3443  s2l_face = ((Dim == 1) ? &svert_lvert :
3444  ((Dim == 2) ? &sedge_ledge : &sface_lface));
3445  }
3446  else
3447  {
3448  s2l_face = &nc_shared_faces;
3449  if (Dim >= 2)
3450  {
3451  // get a list of all shared non-ghost faces
3452  const NCMesh::NCList& sfaces =
3453  (Dim == 3) ? pncmesh->GetSharedFaces() : pncmesh->GetSharedEdges();
3454  const int nfaces = GetNumFaces();
3455  for (unsigned i = 0; i < sfaces.conforming.size(); i++)
3456  {
3457  int index = sfaces.conforming[i].index;
3458  if (index < nfaces) { nc_shared_faces.Append(index); }
3459  }
3460  for (unsigned i = 0; i < sfaces.masters.size(); i++)
3461  {
3462  if (Dim == 2 && WantSkipSharedMaster(sfaces.masters[i])) { continue; }
3463  int index = sfaces.masters[i].index;
3464  if (index < nfaces) { nc_shared_faces.Append(index); }
3465  }
3466  for (unsigned i = 0; i < sfaces.slaves.size(); i++)
3467  {
3468  int index = sfaces.slaves[i].index;
3469  if (index < nfaces) { nc_shared_faces.Append(index); }
3470  }
3471  }
3472  }
3473 
3474  out << "MFEM mesh v1.0\n";
3475 
3476  // optional
3477  out <<
3478  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
3479  "# POINT = 0\n"
3480  "# SEGMENT = 1\n"
3481  "# TRIANGLE = 2\n"
3482  "# SQUARE = 3\n"
3483  "# TETRAHEDRON = 4\n"
3484  "# CUBE = 5\n"
3485  "#\n";
3486 
3487  out << "\ndimension\n" << Dim
3488  << "\n\nelements\n" << NumOfElements << '\n';
3489  for (i = 0; i < NumOfElements; i++)
3490  {
3491  PrintElement(elements[i], out);
3492  }
3493 
3494  int num_bdr_elems = NumOfBdrElements;
3495  if (print_shared && Dim > 1)
3496  {
3497  num_bdr_elems += s2l_face->Size();
3498  }
3499  out << "\nboundary\n" << num_bdr_elems << '\n';
3500  for (i = 0; i < NumOfBdrElements; i++)
3501  {
3502  PrintElement(boundary[i], out);
3503  }
3504 
3505  if (print_shared && Dim > 1)
3506  {
3507  if (bdr_attributes.Size())
3508  {
3509  shared_bdr_attr = bdr_attributes.Max() + MyRank + 1;
3510  }
3511  else
3512  {
3513  shared_bdr_attr = MyRank + 1;
3514  }
3515  for (i = 0; i < s2l_face->Size(); i++)
3516  {
3517  // Modify the attributes of the faces (not used otherwise?)
3518  faces[(*s2l_face)[i]]->SetAttribute(shared_bdr_attr);
3519  PrintElement(faces[(*s2l_face)[i]], out);
3520  }
3521  }
3522  out << "\nvertices\n" << NumOfVertices << '\n';
3523  if (Nodes == NULL)
3524  {
3525  out << spaceDim << '\n';
3526  for (i = 0; i < NumOfVertices; i++)
3527  {
3528  out << vertices[i](0);
3529  for (j = 1; j < spaceDim; j++)
3530  {
3531  out << ' ' << vertices[i](j);
3532  }
3533  out << '\n';
3534  }
3535  out.flush();
3536  }
3537  else
3538  {
3539  out << "\nnodes\n";
3540  Nodes->Save(out);
3541  }
3542 }
3543 
3544 static void dump_element(const Element* elem, Array<int> &data)
3545 {
3546  data.Append(elem->GetGeometryType());
3547 
3548  int nv = elem->GetNVertices();
3549  const int *v = elem->GetVertices();
3550  for (int i = 0; i < nv; i++)
3551  {
3552  data.Append(v[i]);
3553  }
3554 }
3555 
3556 void ParMesh::PrintAsOne(std::ostream &out)
3557 {
3558  int i, j, k, p, nv_ne[2], &nv = nv_ne[0], &ne = nv_ne[1], vc;
3559  const int *v;
3560  MPI_Status status;
3561  Array<double> vert;
3562  Array<int> ints;
3563 
3564  if (MyRank == 0)
3565  {
3566  out << "MFEM mesh v1.0\n";
3567 
3568  // optional
3569  out <<
3570  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
3571  "# POINT = 0\n"
3572  "# SEGMENT = 1\n"
3573  "# TRIANGLE = 2\n"
3574  "# SQUARE = 3\n"
3575  "# TETRAHEDRON = 4\n"
3576  "# CUBE = 5\n"
3577  "#\n";
3578 
3579  out << "\ndimension\n" << Dim;
3580  }
3581 
3582  nv = NumOfElements;
3583  MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm);
3584  if (MyRank == 0)
3585  {
3586  out << "\n\nelements\n" << ne << '\n';
3587  for (i = 0; i < NumOfElements; i++)
3588  {
3589  // processor number + 1 as attribute and geometry type
3590  out << 1 << ' ' << elements[i]->GetGeometryType();
3591  // vertices
3592  nv = elements[i]->GetNVertices();
3593  v = elements[i]->GetVertices();
3594  for (j = 0; j < nv; j++)
3595  {
3596  out << ' ' << v[j];
3597  }
3598  out << '\n';
3599  }
3600  vc = NumOfVertices;
3601  for (p = 1; p < NRanks; p++)
3602  {
3603  MPI_Recv(nv_ne, 2, MPI_INT, p, 444, MyComm, &status);
3604  ints.SetSize(ne);
3605  if (ne)
3606  {
3607  MPI_Recv(&ints[0], ne, MPI_INT, p, 445, MyComm, &status);
3608  }
3609  for (i = 0; i < ne; )
3610  {
3611  // processor number + 1 as attribute and geometry type
3612  out << p+1 << ' ' << ints[i];
3613  // vertices
3614  k = Geometries.GetVertices(ints[i++])->GetNPoints();
3615  for (j = 0; j < k; j++)
3616  {
3617  out << ' ' << vc + ints[i++];
3618  }
3619  out << '\n';
3620  }
3621  vc += nv;
3622  }
3623  }
3624  else
3625  {
3626  // for each element send its geometry type and its vertices
3627  ne = 0;
3628  for (i = 0; i < NumOfElements; i++)
3629  {
3630  ne += 1 + elements[i]->GetNVertices();
3631  }
3632  nv = NumOfVertices;
3633  MPI_Send(nv_ne, 2, MPI_INT, 0, 444, MyComm);
3634 
3635  ints.Reserve(ne);
3636  ints.SetSize(0);
3637  for (i = 0; i < NumOfElements; i++)
3638  {
3639  dump_element(elements[i], ints);
3640  }
3641  MFEM_ASSERT(ints.Size() == ne, "");
3642  if (ne)
3643  {
3644  MPI_Send(&ints[0], ne, MPI_INT, 0, 445, MyComm);
3645  }
3646  }
3647 
3648  // boundary + shared boundary
3649  ne = NumOfBdrElements;
3650  if (!pncmesh)
3651  {
3652  ne += ((Dim == 2) ? shared_edges : shared_faces).Size();
3653  }
3654  else if (Dim > 1)
3655  {
3656  const NCMesh::NCList &list = pncmesh->GetSharedList(Dim - 1);
3657  ne += list.conforming.size() + list.masters.size() + list.slaves.size();
3658  }
3659  ints.Reserve(ne * (1 + 2*(Dim-1))); // just an upper bound
3660  ints.SetSize(0);
3661 
3662  // for each boundary and shared boundary element send its geometry type
3663  // and its vertices
3664  ne = 0;
3665  for (i = j = 0; i < NumOfBdrElements; i++)
3666  {
3667  dump_element(boundary[i], ints); ne++;
3668  }
3669  if (!pncmesh)
3670  {
3671  Array<Element*> &shared = (Dim == 2) ? shared_edges : shared_faces;
3672  for (i = 0; i < shared.Size(); i++)
3673  {
3674  dump_element(shared[i], ints); ne++;
3675  }
3676  }
3677  else if (Dim > 1)
3678  {
3679  const NCMesh::NCList &list = pncmesh->GetSharedList(Dim - 1);
3680  const int nfaces = GetNumFaces();
3681  for (i = 0; i < (int) list.conforming.size(); i++)
3682  {
3683  int index = list.conforming[i].index;
3684  if (index < nfaces) { dump_element(faces[index], ints); ne++; }
3685  }
3686  for (i = 0; i < (int) list.masters.size(); i++)
3687  {
3688  int index = list.masters[i].index;
3689  if (index < nfaces) { dump_element(faces[index], ints); ne++; }
3690  }
3691  for (i = 0; i < (int) list.slaves.size(); i++)
3692  {
3693  int index = list.slaves[i].index;
3694  if (index < nfaces) { dump_element(faces[index], ints); ne++; }
3695  }
3696  }
3697 
3698  MPI_Reduce(&ne, &k, 1, MPI_INT, MPI_SUM, 0, MyComm);
3699  if (MyRank == 0)
3700  {
3701  out << "\nboundary\n" << k << '\n';
3702  vc = 0;
3703  for (p = 0; p < NRanks; p++)
3704  {
3705  if (p)
3706  {
3707  MPI_Recv(nv_ne, 2, MPI_INT, p, 446, MyComm, &status);
3708  ints.SetSize(ne);
3709  if (ne)
3710  {
3711  MPI_Recv(ints.GetData(), ne, MPI_INT, p, 447, MyComm, &status);
3712  }
3713  }
3714  else
3715  {
3716  ne = ints.Size();
3717  nv = NumOfVertices;
3718  }
3719  for (i = 0; i < ne; )
3720  {
3721  // processor number + 1 as bdr. attr. and bdr. geometry type
3722  out << p+1 << ' ' << ints[i];
3723  k = Geometries.NumVerts[ints[i++]];
3724  // vertices
3725  for (j = 0; j < k; j++)
3726  {
3727  out << ' ' << vc + ints[i++];
3728  }
3729  out << '\n';
3730  }
3731  vc += nv;
3732  }
3733  }
3734  else
3735  {
3736  nv = NumOfVertices;
3737  ne = ints.Size();
3738  MPI_Send(nv_ne, 2, MPI_INT, 0, 446, MyComm);
3739  if (ne)
3740  {
3741  MPI_Send(ints.GetData(), ne, MPI_INT, 0, 447, MyComm);
3742  }
3743  }
3744 
3745  // vertices / nodes
3746  MPI_Reduce(&NumOfVertices, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm);
3747  if (MyRank == 0)
3748  {
3749  out << "\nvertices\n" << nv << '\n';
3750  }
3751  if (Nodes == NULL)
3752  {
3753  if (MyRank == 0)
3754  {
3755  out << spaceDim << '\n';
3756  for (i = 0; i < NumOfVertices; i++)
3757  {
3758  out << vertices[i](0);
3759  for (j = 1; j < spaceDim; j++)
3760  {
3761  out << ' ' << vertices[i](j);
3762  }
3763  out << '\n';
3764  }
3765  for (p = 1; p < NRanks; p++)
3766  {
3767  MPI_Recv(&nv, 1, MPI_INT, p, 448, MyComm, &status);
3768  vert.SetSize(nv*spaceDim);
3769  if (nv)
3770  {
3771  MPI_Recv(&vert[0], nv*spaceDim, MPI_DOUBLE, p, 449, MyComm, &status);
3772  }
3773  for (i = 0; i < nv; i++)
3774  {
3775  out << vert[i*spaceDim];
3776  for (j = 1; j < spaceDim; j++)
3777  {
3778  out << ' ' << vert[i*spaceDim+j];
3779  }
3780  out << '\n';
3781  }
3782  }
3783  out.flush();
3784  }
3785  else
3786  {
3787  MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 448, MyComm);
3789  for (i = 0; i < NumOfVertices; i++)
3790  {
3791  for (j = 0; j < spaceDim; j++)
3792  {
3793  vert[i*spaceDim+j] = vertices[i](j);
3794  }
3795  }
3796  if (NumOfVertices)
3797  {
3798  MPI_Send(&vert[0], NumOfVertices*spaceDim, MPI_DOUBLE, 0, 449, MyComm);
3799  }
3800  }
3801  }
3802  else
3803  {
3804  if (MyRank == 0)
3805  {
3806  out << "\nnodes\n";
3807  }
3808  ParGridFunction *pnodes = dynamic_cast<ParGridFunction *>(Nodes);
3809  if (pnodes)
3810  {
3811  pnodes->SaveAsOne(out);
3812  }
3813  else
3814  {
3815  ParFiniteElementSpace *pfes =
3816  dynamic_cast<ParFiniteElementSpace *>(Nodes->FESpace());
3817  if (pfes)
3818  {
3819  // create a wrapper ParGridFunction
3820  ParGridFunction ParNodes(pfes, Nodes);
3821  ParNodes.SaveAsOne(out);
3822  }
3823  else
3824  {
3825  mfem_error("ParMesh::PrintAsOne : Nodes have no parallel info!");
3826  }
3827  }
3828  }
3829 }
3830 
3831 void ParMesh::PrintAsOneXG(std::ostream &out)
3832 {
3833  MFEM_ASSERT(Dim == spaceDim, "2D Manifolds not supported.");
3834  if (Dim == 3 && meshgen == 1)
3835  {
3836  int i, j, k, nv, ne, p;
3837  const int *ind, *v;
3838  MPI_Status status;
3839  Array<double> vert;
3840  Array<int> ints;
3841 
3842  if (MyRank == 0)
3843  {
3844  out << "NETGEN_Neutral_Format\n";
3845  // print the vertices
3846  ne = NumOfVertices;
3847  MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm);
3848  out << nv << '\n';
3849  for (i = 0; i < NumOfVertices; i++)
3850  {
3851  for (j = 0; j < Dim; j++)
3852  {
3853  out << " " << vertices[i](j);
3854  }
3855  out << '\n';
3856  }
3857  for (p = 1; p < NRanks; p++)
3858  {
3859  MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status);
3860  vert.SetSize(Dim*nv);
3861  MPI_Recv(&vert[0], Dim*nv, MPI_DOUBLE, p, 445, MyComm, &status);
3862  for (i = 0; i < nv; i++)
3863  {
3864  for (j = 0; j < Dim; j++)
3865  {
3866  out << " " << vert[Dim*i+j];
3867  }
3868  out << '\n';
3869  }
3870  }
3871 
3872  // print the elements
3873  nv = NumOfElements;
3874  MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm);
3875  out << ne << '\n';
3876  for (i = 0; i < NumOfElements; i++)
3877  {
3878  nv = elements[i]->GetNVertices();
3879  ind = elements[i]->GetVertices();
3880  out << 1;
3881  for (j = 0; j < nv; j++)
3882  {
3883  out << " " << ind[j]+1;
3884  }
3885  out << '\n';
3886  }
3887  k = NumOfVertices;
3888  for (p = 1; p < NRanks; p++)
3889  {
3890  MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status);
3891  MPI_Recv(&ne, 1, MPI_INT, p, 446, MyComm, &status);
3892  ints.SetSize(4*ne);
3893  MPI_Recv(&ints[0], 4*ne, MPI_INT, p, 447, MyComm, &status);
3894  for (i = 0; i < ne; i++)
3895  {
3896  out << p+1;
3897  for (j = 0; j < 4; j++)
3898  {
3899  out << " " << k+ints[i*4+j]+1;
3900  }
3901  out << '\n';
3902  }
3903  k += nv;
3904  }
3905  // print the boundary + shared faces information
3906  nv = NumOfBdrElements + shared_faces.Size();
3907  MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm);
3908  out << ne << '\n';
3909  // boundary
3910  for (i = 0; i < NumOfBdrElements; i++)
3911  {
3912  nv = boundary[i]->GetNVertices();
3913  ind = boundary[i]->GetVertices();
3914  out << 1;
3915  for (j = 0; j < nv; j++)
3916  {
3917  out << " " << ind[j]+1;
3918  }
3919  out << '\n';
3920  }
3921  // shared faces
3922  for (i = 0; i < shared_faces.Size(); i++)
3923  {
3924  nv = shared_faces[i]->GetNVertices();
3925  ind = shared_faces[i]->GetVertices();
3926  out << 1;
3927  for (j = 0; j < nv; j++)
3928  {
3929  out << " " << ind[j]+1;
3930  }
3931  out << '\n';
3932  }
3933  k = NumOfVertices;
3934  for (p = 1; p < NRanks; p++)
3935  {
3936  MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status);
3937  MPI_Recv(&ne, 1, MPI_INT, p, 446, MyComm, &status);
3938  ints.SetSize(3*ne);
3939  MPI_Recv(&ints[0], 3*ne, MPI_INT, p, 447, MyComm, &status);
3940  for (i = 0; i < ne; i++)
3941  {
3942  out << p+1;
3943  for (j = 0; j < 3; j++)
3944  {
3945  out << " " << k+ints[i*3+j]+1;
3946  }
3947  out << '\n';
3948  }
3949  k += nv;
3950  }
3951  }
3952  else
3953  {
3954  ne = NumOfVertices;
3955  MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm);
3956  MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm);
3957  vert.SetSize(Dim*NumOfVertices);
3958  for (i = 0; i < NumOfVertices; i++)
3959  for (j = 0; j < Dim; j++)
3960  {
3961  vert[Dim*i+j] = vertices[i](j);
3962  }
3963  MPI_Send(&vert[0], Dim*NumOfVertices, MPI_DOUBLE,
3964  0, 445, MyComm);
3965  // elements
3966  ne = NumOfElements;
3967  MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm);
3968  MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm);
3969  MPI_Send(&NumOfElements, 1, MPI_INT, 0, 446, MyComm);
3970  ints.SetSize(NumOfElements*4);
3971  for (i = 0; i < NumOfElements; i++)
3972  {
3973  v = elements[i]->GetVertices();
3974  for (j = 0; j < 4; j++)
3975  {
3976  ints[4*i+j] = v[j];
3977  }
3978  }
3979  MPI_Send(&ints[0], 4*NumOfElements, MPI_INT, 0, 447, MyComm);
3980  // boundary + shared faces
3981  nv = NumOfBdrElements + shared_faces.Size();
3982  MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm);
3983  MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm);
3984  ne = NumOfBdrElements + shared_faces.Size();
3985  MPI_Send(&ne, 1, MPI_INT, 0, 446, MyComm);
3986  ints.SetSize(3*ne);
3987  for (i = 0; i < NumOfBdrElements; i++)
3988  {
3989  v = boundary[i]->GetVertices();
3990  for (j = 0; j < 3; j++)
3991  {
3992  ints[3*i+j] = v[j];
3993  }
3994  }
3995  for ( ; i < ne; i++)
3996  {
3997  v = shared_faces[i-NumOfBdrElements]->GetVertices();
3998  for (j = 0; j < 3; j++)
3999  {
4000  ints[3*i+j] = v[j];
4001  }
4002  }
4003  MPI_Send(&ints[0], 3*ne, MPI_INT, 0, 447, MyComm);
4004  }
4005  }
4006 
4007  if (Dim == 3 && meshgen == 2)
4008  {
4009  int i, j, k, nv, ne, p;
4010  const int *ind, *v;
4011  MPI_Status status;
4012  Array<double> vert;
4013  Array<int> ints;
4014 
4015  int TG_nv, TG_ne, TG_nbe;
4016 
4017  if (MyRank == 0)
4018  {
4019  MPI_Reduce(&NumOfVertices, &TG_nv, 1, MPI_INT, MPI_SUM, 0, MyComm);
4020  MPI_Reduce(&NumOfElements, &TG_ne, 1, MPI_INT, MPI_SUM, 0, MyComm);
4021  nv = NumOfBdrElements + shared_faces.Size();
4022  MPI_Reduce(&nv, &TG_nbe, 1, MPI_INT, MPI_SUM, 0, MyComm);
4023 
4024  out << "TrueGrid\n"
4025  << "1 " << TG_nv << " " << TG_ne << " 0 0 0 0 0 0 0\n"
4026  << "0 0 0 1 0 0 0 0 0 0 0\n"
4027  << "0 0 " << TG_nbe << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
4028  << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
4029  << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
4030 
4031  // print the vertices
4032  nv = TG_nv;
4033  for (i = 0; i < NumOfVertices; i++)
4034  out << i+1 << " 0.0 " << vertices[i](0) << " " << vertices[i](1)
4035  << " " << vertices[i](2) << " 0.0\n";
4036  for (p = 1; p < NRanks; p++)
4037  {
4038  MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status);
4039  vert.SetSize(Dim*nv);
4040  MPI_Recv(&vert[0], Dim*nv, MPI_DOUBLE, p, 445, MyComm, &status);
4041  for (i = 0; i < nv; i++)
4042  out << i+1 << " 0.0 " << vert[Dim*i] << " " << vert[Dim*i+1]
4043  << " " << vert[Dim*i+2] << " 0.0\n";
4044  }
4045 
4046  // print the elements
4047  ne = TG_ne;
4048  for (i = 0; i < NumOfElements; i++)
4049  {
4050  nv = elements[i]->GetNVertices();
4051  ind = elements[i]->GetVertices();
4052  out << i+1 << " " << 1;
4053  for (j = 0; j < nv; j++)
4054  {
4055  out << " " << ind[j]+1;
4056  }
4057  out << '\n';
4058  }
4059  k = NumOfVertices;
4060  for (p = 1; p < NRanks; p++)
4061  {
4062  MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status);
4063  MPI_Recv(&ne, 1, MPI_INT, p, 446, MyComm, &status);
4064  ints.SetSize(8*ne);
4065  MPI_Recv(&ints[0], 8*ne, MPI_INT, p, 447, MyComm, &status);
4066  for (i = 0; i < ne; i++)
4067  {
4068  out << i+1 << " " << p+1;
4069  for (j = 0; j < 8; j++)
4070  {
4071  out << " " << k+ints[i*8+j]+1;
4072  }
4073  out << '\n';
4074  }
4075  k += nv;
4076  }
4077 
4078  // print the boundary + shared faces information
4079  ne = TG_nbe;
4080  // boundary
4081  for (i = 0; i < NumOfBdrElements; i++)
4082  {
4083  nv = boundary[i]->GetNVertices();
4084  ind = boundary[i]->GetVertices();
4085  out << 1;
4086  for (j = 0; j < nv; j++)
4087  {
4088  out << " " << ind[j]+1;
4089  }
4090  out << " 1.0 1.0 1.0 1.0\n";
4091  }
4092  // shared faces
4093  for (i = 0; i < shared_faces.Size(); i++)
4094  {
4095  nv = shared_faces[i]->GetNVertices();
4096  ind = shared_faces[i]->GetVertices();
4097  out << 1;
4098  for (j = 0; j < nv; j++)
4099  {
4100  out << " " << ind[j]+1;
4101  }
4102  out << " 1.0 1.0 1.0 1.0\n";
4103  }
4104  k = NumOfVertices;
4105  for (p = 1; p < NRanks; p++)
4106  {
4107  MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status);
4108  MPI_Recv(&ne, 1, MPI_INT, p, 446, MyComm, &status);
4109  ints.SetSize(4*ne);
4110  MPI_Recv(&ints[0], 4*ne, MPI_INT, p, 447, MyComm, &status);
4111  for (i = 0; i < ne; i++)
4112  {
4113  out << p+1;
4114  for (j = 0; j < 4; j++)
4115  {
4116  out << " " << k+ints[i*4+j]+1;
4117  }
4118  out << " 1.0 1.0 1.0 1.0\n";
4119  }
4120  k += nv;
4121  }
4122  }
4123  else
4124  {
4125  MPI_Reduce(&NumOfVertices, &TG_nv, 1, MPI_INT, MPI_SUM, 0, MyComm);
4126  MPI_Reduce(&NumOfElements, &TG_ne, 1, MPI_INT, MPI_SUM, 0, MyComm);
4127  nv = NumOfBdrElements + shared_faces.Size();
4128  MPI_Reduce(&nv, &TG_nbe, 1, MPI_INT, MPI_SUM, 0, MyComm);
4129 
4130  MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm);
4131  vert.SetSize(Dim*NumOfVertices);
4132  for (i = 0; i < NumOfVertices; i++)
4133  for (j = 0; j < Dim; j++)
4134  {
4135  vert[Dim*i+j] = vertices[i](j);
4136  }
4137  MPI_Send(&vert[0], Dim*NumOfVertices, MPI_DOUBLE, 0, 445, MyComm);
4138  // elements
4139  MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm);
4140  MPI_Send(&NumOfElements, 1, MPI_INT, 0, 446, MyComm);
4141  ints.SetSize(NumOfElements*8);
4142  for (i = 0; i < NumOfElements; i++)
4143  {
4144  v = elements[i]->GetVertices();
4145  for (j = 0; j < 8; j++)
4146  {
4147  ints[8*i+j] = v[j];
4148  }
4149  }
4150  MPI_Send(&ints[0], 8*NumOfElements, MPI_INT, 0, 447, MyComm);
4151  // boundary + shared faces
4152  MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm);
4153  ne = NumOfBdrElements + shared_faces.Size();
4154  MPI_Send(&ne, 1, MPI_INT, 0, 446, MyComm);
4155  ints.SetSize(4*ne);
4156  for (i = 0; i < NumOfBdrElements; i++)
4157  {
4158  v = boundary[i]->GetVertices();
4159  for (j = 0; j < 4; j++)
4160  {
4161  ints[4*i+j] = v[j];
4162  }
4163  }
4164  for ( ; i < ne; i++)
4165  {
4166  v = shared_faces[i-NumOfBdrElements]->GetVertices();
4167  for (j = 0; j < 4; j++)
4168  {
4169  ints[4*i+j] = v[j];
4170  }
4171  }
4172  MPI_Send(&ints[0], 4*ne, MPI_INT, 0, 447, MyComm);
4173  }
4174  }
4175 
4176  if (Dim == 2)
4177  {
4178  int i, j, k, attr, nv, ne, p;
4179  Array<int> v;
4180  MPI_Status status;
4181  Array<double> vert;
4182  Array<int> ints;
4183 
4184 
4185  if (MyRank == 0)
4186  {
4187  out << "areamesh2\n\n";
4188 
4189  // print the boundary + shared edges information
4190  nv = NumOfBdrElements + shared_edges.Size();
4191  MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm);
4192  out << ne << '\n';
4193  // boundary
4194  for (i = 0; i < NumOfBdrElements; i++)
4195  {
4196  attr = boundary[i]->GetAttribute();
4197  boundary[i]->GetVertices(v);
4198  out << attr << " ";
4199  for (j = 0; j < v.Size(); j++)
4200  {
4201  out << v[j] + 1 << " ";
4202  }
4203  out << '\n';
4204  }
4205  // shared edges
4206  for (i = 0; i < shared_edges.Size(); i++)
4207  {
4208  attr = shared_edges[i]->GetAttribute();
4209  shared_edges[i]->GetVertices(v);
4210  out << attr << " ";
4211  for (j = 0; j < v.Size(); j++)
4212  {
4213  out << v[j] + 1 << " ";
4214  }
4215  out << '\n';
4216  }
4217  k = NumOfVertices;
4218  for (p = 1; p < NRanks; p++)
4219  {
4220  MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status);
4221  MPI_Recv(&ne, 1, MPI_INT, p, 446, MyComm, &status);
4222  ints.SetSize(2*ne);
4223  MPI_Recv(&ints[0], 2*ne, MPI_INT, p, 447, MyComm, &status);
4224  for (i = 0; i < ne; i++)
4225  {
4226  out << p+1;
4227  for (j = 0; j < 2; j++)
4228  {
4229  out << " " << k+ints[i*2+j]+1;
4230  }
4231  out << '\n';
4232  }
4233  k += nv;
4234  }
4235 
4236  // print the elements
4237  nv = NumOfElements;
4238  MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm);
4239  out << ne << '\n';
4240  for (i = 0; i < NumOfElements; i++)
4241  {
4242  // attr = elements[i]->GetAttribute(); // not used
4243  elements[i]->GetVertices(v);
4244  out << 1 << " " << 3 << " ";
4245  for (j = 0; j < v.Size(); j++)
4246  {
4247  out << v[j] + 1 << " ";
4248  }
4249  out << '\n';
4250  }
4251  k = NumOfVertices;
4252  for (p = 1; p < NRanks; p++)
4253  {
4254  MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status);
4255  MPI_Recv(&ne, 1, MPI_INT, p, 446, MyComm, &status);
4256  ints.SetSize(3*ne);
4257  MPI_Recv(&ints[0], 3*ne, MPI_INT, p, 447, MyComm, &status);
4258  for (i = 0; i < ne; i++)
4259  {
4260  out << p+1 << " " << 3;
4261  for (j = 0; j < 3; j++)
4262  {
4263  out << " " << k+ints[i*3+j]+1;
4264  }
4265  out << '\n';
4266  }
4267  k += nv;
4268  }
4269 
4270  // print the vertices
4271  ne = NumOfVertices;
4272  MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm);
4273  out << nv << '\n';
4274  for (i = 0; i < NumOfVertices; i++)
4275  {
4276  for (j = 0; j < Dim; j++)
4277  {
4278  out << vertices[i](j) << " ";
4279  }
4280  out << '\n';
4281  }
4282  for (p = 1; p < NRanks; p++)
4283  {
4284  MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status);
4285  vert.SetSize(Dim*nv);
4286  MPI_Recv(&vert[0], Dim*nv, MPI_DOUBLE, p, 445, MyComm, &status);
4287  for (i = 0; i < nv; i++)
4288  {
4289  for (j = 0; j < Dim; j++)
4290  {
4291  out << " " << vert[Dim*i+j];
4292  }
4293  out << '\n';
4294  }
4295  }
4296  }
4297  else
4298  {
4299  // boundary + shared faces
4300  nv = NumOfBdrElements + shared_edges.Size();
4301  MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm);
4302  MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm);
4303  ne = NumOfBdrElements + shared_edges.Size();
4304  MPI_Send(&ne, 1, MPI_INT, 0, 446, MyComm);
4305  ints.SetSize(2*ne);
4306  for (i = 0; i < NumOfBdrElements; i++)
4307  {
4308  boundary[i]->GetVertices(v);
4309  for (j = 0; j < 2; j++)
4310  {
4311  ints[2*i+j] = v[j];
4312  }
4313  }
4314  for ( ; i < ne; i++)
4315  {
4316  shared_edges[i-NumOfBdrElements]->GetVertices(v);
4317  for (j = 0; j < 2; j++)
4318  {
4319  ints[2*i+j] = v[j];
4320  }
4321  }
4322  MPI_Send(&ints[0], 2*ne, MPI_INT, 0, 447, MyComm);
4323  // elements
4324  ne = NumOfElements;
4325  MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm);
4326  MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm);
4327  MPI_Send(&NumOfElements, 1, MPI_INT, 0, 446, MyComm);
4328  ints.SetSize(NumOfElements*3);
4329  for (i = 0; i < NumOfElements; i++)
4330  {
4331  elements[i]->GetVertices(v);
4332  for (j = 0; j < 3; j++)
4333  {
4334  ints[3*i+j] = v[j];
4335  }
4336  }
4337  MPI_Send(&ints[0], 3*NumOfElements, MPI_INT, 0, 447, MyComm);
4338  // vertices
4339  ne = NumOfVertices;
4340  MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm);
4341  MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm);
4342  vert.SetSize(Dim*NumOfVertices);
4343  for (i = 0; i < NumOfVertices; i++)
4344  for (j = 0; j < Dim; j++)
4345  {
4346  vert[Dim*i+j] = vertices[i](j);
4347  }
4348  MPI_Send(&vert[0], Dim*NumOfVertices, MPI_DOUBLE,
4349  0, 445, MyComm);
4350  }
4351  }
4352 }
4353 
4354 void ParMesh::GetBoundingBox(Vector &gp_min, Vector &gp_max, int ref)
4355 {
4356  int sdim;
4357  Vector p_min, p_max;
4358 
4359  this->Mesh::GetBoundingBox(p_min, p_max, ref);
4360 
4361  sdim = SpaceDimension();
4362 
4363  gp_min.SetSize(sdim);
4364  gp_max.SetSize(sdim);
4365 
4366  MPI_Allreduce(p_min.GetData(), gp_min, sdim, MPI_DOUBLE, MPI_MIN, MyComm);
4367  MPI_Allreduce(p_max.GetData(), gp_max, sdim, MPI_DOUBLE, MPI_MAX, MyComm);
4368 }
4369 
4370 void ParMesh::GetCharacteristics(double &gh_min, double &gh_max,
4371  double &gk_min, double &gk_max)
4372 {
4373  double h_min, h_max, kappa_min, kappa_max;
4374 
4375  this->Mesh::GetCharacteristics(h_min, h_max, kappa_min, kappa_max);
4376 
4377  MPI_Allreduce(&h_min, &gh_min, 1, MPI_DOUBLE, MPI_MIN, MyComm);
4378  MPI_Allreduce(&h_max, &gh_max, 1, MPI_DOUBLE, MPI_MAX, MyComm);
4379  MPI_Allreduce(&kappa_min, &gk_min, 1, MPI_DOUBLE, MPI_MIN, MyComm);
4380  MPI_Allreduce(&kappa_max, &gk_max, 1, MPI_DOUBLE, MPI_MAX, MyComm);
4381 }
4382 
4383 void ParMesh::PrintInfo(std::ostream &out)
4384 {
4385  int i;
4386  DenseMatrix J(Dim);
4387  double h_min, h_max, kappa_min, kappa_max, h, kappa;
4388 
4389  if (MyRank == 0)
4390  {
4391  out << "Parallel Mesh Stats:" << '\n';
4392  }
4393 
4394  for (i = 0; i < NumOfElements; i++)
4395  {
4396  GetElementJacobian(i, J);
4397  h = pow(fabs(J.Det()), 1.0/double(Dim));
4398  kappa = J.CalcSingularvalue(0) / J.CalcSingularvalue(Dim-1);
4399  if (i == 0)
4400  {
4401  h_min = h_max = h;
4402  kappa_min = kappa_max = kappa;
4403  }
4404  else
4405  {
4406  if (h < h_min) { h_min = h; }
4407  if (h > h_max) { h_max = h; }
4408  if (kappa < kappa_min) { kappa_min = kappa; }
4409  if (kappa > kappa_max) { kappa_max = kappa; }
4410  }
4411  }
4412 
4413  double gh_min, gh_max, gk_min, gk_max;
4414  MPI_Reduce(&h_min, &gh_min, 1, MPI_DOUBLE, MPI_MIN, 0, MyComm);
4415  MPI_Reduce(&h_max, &gh_max, 1, MPI_DOUBLE, MPI_MAX, 0, MyComm);
4416  MPI_Reduce(&kappa_min, &gk_min, 1, MPI_DOUBLE, MPI_MIN, 0, MyComm);
4417  MPI_Reduce(&kappa_max, &gk_max, 1, MPI_DOUBLE, MPI_MAX, 0, MyComm);
4418 
4419  long ldata[5]; // vert, edge, face, elem, neighbors;
4420  long mindata[5], maxdata[5], sumdata[5];
4421 
4422  // count locally owned vertices, edges, and faces
4423  ldata[0] = GetNV();
4424  ldata[1] = GetNEdges();
4425  ldata[2] = GetNFaces();
4426  ldata[3] = GetNE();
4427  ldata[4] = gtopo.GetNumNeighbors()-1;
4428  for (int gr = 1; gr < GetNGroups(); gr++)
4429  if (!gtopo.IAmMaster(gr)) // we are not the master
4430  {
4431  ldata[0] -= group_svert.RowSize(gr-1);
4432  ldata[1] -= group_sedge.RowSize(gr-1);
4433  ldata[2] -= group_sface.RowSize(gr-1);
4434  }
4435 
4436  MPI_Reduce(ldata, mindata, 5, MPI_LONG, MPI_MIN, 0, MyComm);
4437  MPI_Reduce(ldata, sumdata, 5, MPI_LONG, MPI_SUM, 0, MyComm);
4438  MPI_Reduce(ldata, maxdata, 5, MPI_LONG, MPI_MAX, 0, MyComm);
4439 
4440  if (MyRank == 0)
4441  {
4442  out << '\n'
4443  << " "
4444  << setw(12) << "minimum"
4445  << setw(12) << "average"
4446  << setw(12) << "maximum"
4447  << setw(12) << "total" << '\n';
4448  out << " vertices "
4449  << setw(12) << mindata[0]
4450  << setw(12) << sumdata[0]/NRanks
4451  << setw(12) << maxdata[0]
4452  << setw(12) << sumdata[0] << '\n';
4453  out << " edges "
4454  << setw(12) << mindata[1]
4455  << setw(12) << sumdata[1]/NRanks
4456  << setw(12) << maxdata[1]
4457  << setw(12) << sumdata[1] << '\n';
4458  if (Dim == 3)
4459  out << " faces "
4460  << setw(12) << mindata[2]
4461  << setw(12) << sumdata[2]/NRanks
4462  << setw(12) << maxdata[2]
4463  << setw(12) << sumdata[2] << '\n';
4464  out << " elements "
4465  << setw(12) << mindata[3]
4466  << setw(12) << sumdata[3]/NRanks
4467  << setw(12) << maxdata[3]
4468  << setw(12) << sumdata[3] << '\n';
4469  out << " neighbors "
4470  << setw(12) << mindata[4]
4471  << setw(12) << sumdata[4]/NRanks
4472  << setw(12) << maxdata[4] << '\n';
4473  out << '\n'
4474  << " "
4475  << setw(12) << "minimum"
4476  << setw(12) << "maximum" << '\n';
4477  out << " h "
4478  << setw(12) << gh_min
4479  << setw(12) << gh_max << '\n';
4480  out << " kappa "
4481  << setw(12) << gk_min
4482  << setw(12) << gk_max << '\n';
4483  out << std::flush;
4484  }
4485 }
4486 
4487 long ParMesh::ReduceInt(int value) const
4488 {
4489  long local = value, global;
4490  MPI_Allreduce(&local, &global, 1, MPI_LONG, MPI_SUM, MyComm);
4491  return global;
4492 }
4493 
4494 void ParMesh::ParPrint(ostream &out) const
4495 {
4496  if (NURBSext || pncmesh)
4497  {
4498  // TODO: AMR meshes, NURBS meshes.
4499  Print(out);
4500  return;
4501  }
4502 
4503  // Write out serial mesh. Tell serial mesh to deliniate the end of it's
4504  // output with 'mfem_serial_mesh_end' instead of 'mfem_mesh_end', as we will
4505  // be adding additional parallel mesh information.
4506  Printer(out, "mfem_serial_mesh_end");
4507 
4508  // write out group topology info.
4509  gtopo.Save(out);
4510 
4511  out << "\ntotal_shared_vertices " << svert_lvert.Size() << '\n';
4512  if (Dim >= 2)
4513  {
4514  out << "total_shared_edges " << shared_edges.Size() << '\n';
4515  }
4516  if (Dim >= 3)
4517  {
4518  out << "total_shared_faces " << shared_faces.Size() << '\n';
4519  }
4520  for (int gr = 1; gr < GetNGroups(); gr++)
4521  {
4522  {
4523  const int nv = group_svert.RowSize(gr-1);
4524  const int *sv = group_svert.GetRow(gr-1);
4525  out << "\n#group " << gr << "\nshared_vertices " << nv << '\n';
4526  for (int i = 0; i < nv; i++)
4527  {
4528  out << svert_lvert[sv[i]] << '\n';
4529  }
4530  }
4531  if (Dim >= 2)
4532  {
4533  const int ne = group_sedge.RowSize(gr-1);
4534  const int *se = group_sedge.GetRow(gr-1);
4535  out << "\nshared_edges " << ne << '\n';
4536  for (int i = 0; i < ne; i++)
4537  {
4538  const int *v = shared_edges[se[i]]->GetVertices();
4539  out << v[0] << ' ' << v[1] << '\n';
4540  }
4541  }
4542  if (Dim >= 3)
4543  {
4544  const int nf = group_sface.RowSize(gr-1);
4545  const int *sf = group_sface.GetRow(gr-1);
4546  out << "\nshared_faces " << nf << '\n';
4547  for (int i = 0; i < nf; i++)
4548  {
4550  }
4551  }
4552  }
4553 
4554  // Write out section end tag for mesh.
4555  out << "\nmfem_mesh_end" << endl;
4556 }
4557 
4558 int ParMesh::FindPoints(DenseMatrix& point_mat, Array<int>& elem_id,
4559  Array<IntegrationPoint>& ip, bool warn,
4560  InverseElementTransformation *inv_trans)
4561 {
4562  const int npts = point_mat.Width();
4563  if (npts == 0) { return 0; }
4564 
4565  const bool no_warn = false;
4566  Mesh::FindPoints(point_mat, elem_id, ip, no_warn, inv_trans);
4567 
4568  // If multiple processors find the same point, we need to choose only one of
4569  // the processors to mark that point as found.
4570  // Here, we choose the processor with the minimal rank.
4571 
4572  Array<int> my_point_rank(npts), glob_point_rank(npts);
4573  for (int k = 0; k < npts; k++)
4574  {
4575  my_point_rank[k] = (elem_id[k] == -1) ? NRanks : MyRank;
4576  }
4577 
4578  MPI_Allreduce(my_point_rank.GetData(), glob_point_rank.GetData(), npts,
4579  MPI_INT, MPI_MIN, MyComm);
4580 
4581  int pts_found = 0;
4582  for (int k = 0; k < npts; k++)
4583  {
4584  if (glob_point_rank[k] == NRanks) { elem_id[k] = -1; }
4585  else
4586  {
4587  pts_found++;
4588  if (glob_point_rank[k] != MyRank) { elem_id[k] = -2; }
4589  }
4590  }
4591  if (warn && pts_found != npts && MyRank == 0)
4592  {
4593  MFEM_WARNING((npts-pts_found) << " points were not found");
4594  }
4595  return pts_found;
4596 }
4597 
4599 {
4600  delete pncmesh;
4601  ncmesh = pncmesh = NULL;
4602 
4604 
4605  for (int i = 0; i < shared_faces.Size(); i++)
4606  {
4608  }
4609  for (int i = 0; i < shared_edges.Size(); i++)
4610  {
4612  }
4613 
4614  // The Mesh destructor is called automatically
4615 }
4616 
4617 }
4618 
4619 #endif
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition: intrules.hpp:232
Abstract class for Finite Elements.
Definition: fe.hpp:140
int GetNFaceNeighbors() const
Definition: pmesh.hpp:161
void PrintAsOneXG(std::ostream &out=mfem::out)
Old mesh format (Netgen/Truegrid) version of &#39;PrintAsOne&#39;.
Definition: pmesh.cpp:3831
void Create(ListOfIntegerSets &groups, int mpitag)
void Loader(std::istream &input, int generate_edges=0, std::string parse_tag="")
Definition: mesh.cpp:2618
Ordering::Type GetOrdering() const
Return the ordering method.
Definition: fespace.hpp:265
void MultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
Multiply a matrix A with the transpose of a matrix B: A*Bt.
Definition: densemat.cpp:3356
int Size() const
Logical size of the array.
Definition: array.hpp:133
void SetSubVector(const Array< int > &dofs, const double value)
Set the entries listed in dofs to the given value.
Definition: vector.cpp:494
void Recreate(const int n, const int *p)
Definition: sets.cpp:59
ElementTransformation * Face
Definition: eltrans.hpp:347
int * GetJ()
Definition: table.hpp:114
Class for an integration rule - an Array of IntegrationPoint.
Definition: intrules.hpp:83
DenseMatrix & GetPointMat()
Read and write access to the underlying point matrix describing the transformation.
Definition: eltrans.hpp:312
const double * GetVertex(int i) const
Return pointer to vertex i&#39;s coordinates.
Definition: mesh.hpp:651
Class for grid function - Vector with associated FE space.
Definition: gridfunc.hpp:27
virtual ~ParMesh()
Definition: pmesh.cpp:4598
void Bcast(T *ldata, int layout) const
Broadcast within each group where the master is the root.
void UseExternalData(double *ext_data, int i, int j, int k)
Definition: densemat.hpp:691
void FreeElement(Element *E)
Definition: mesh.cpp:8550
void DerefineMesh(const Array< int > &derefinements)
Derefine elements once a list of derefinements is known.
Definition: mesh.cpp:6075
virtual void Update(bool want_transform=true)
Definition: fespace.cpp:1719
int CheckElementOrientation(bool fix_it=true)
Check the orientation of the elements.
Definition: mesh.cpp:3389
int NRanks
Definition: pmesh.hpp:42
void SetSize(int dim, int connections_per_row)
Set the size and the number of connections for the table.
Definition: table.cpp:126
virtual Element * Duplicate(Mesh *m) const =0
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
Definition: mesh.cpp:3782
void AddColumnsInRow(int r, int ncol)
Definition: table.hpp:78
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
Definition: table.cpp:84
virtual void Project(Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
Definition: fe.cpp:124
virtual void GetVertices(Array< int > &v) const =0
Returns element&#39;s vertices.
void GetFaceElements(int Face, int *Elem1, int *Elem2)
Definition: mesh.cpp:767
Array< Element * > boundary
Definition: mesh.hpp:74
int * GeneratePartitioning(int nparts, int part_method=1)
Definition: mesh.cpp:4640
int GetNGroups() const
Definition: pmesh.hpp:142
CoarseFineTransformations CoarseFineTr
Definition: mesh.hpp:146
virtual void ReorientTetMesh()
See the remarks for the serial version in mesh.hpp.
Definition: pmesh.cpp:2071
int own_nodes
Definition: mesh.hpp:152
bool Conforming() const
Definition: mesh.hpp:1013
void SetSize(int s)
Resize the vector to size s.
Definition: vector.hpp:328
int GetNBE() const
Returns number of boundary elements.
Definition: mesh.hpp:621
void DeleteLazyTables()
Definition: mesh.cpp:893
IsoparametricTransformation Transformation
Definition: mesh.hpp:141
void GetElementVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom in array dofs for i&#39;th element.
Definition: fespace.cpp:171
void GetCharacteristics(double &h_min, double &h_max, double &kappa_min, double &kappa_max, Vector *Vh=NULL, Vector *Vk=NULL)
Definition: mesh.cpp:172
int GetFaceGeometryType(int Face) const
Definition: mesh.cpp:779
void MakeOwner(FiniteElementCollection *_fec)
Make the GridFunction the owner of &#39;fec&#39; and &#39;fes&#39;.
Definition: gridfunc.hpp:96
Array< Element * > face_nbr_elements
Definition: pmesh.hpp:134
const Geometry::Type geom
Definition: ex1.cpp:40
double Det() const
Definition: densemat.cpp:460
void GetFaceNeighbors(class ParMesh &pmesh)
Definition: pncmesh.cpp:799
int NumOfEdges
Definition: mesh.hpp:57
Lists all edges/faces in the nonconforming mesh.
Definition: ncmesh.hpp:169
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition: operator.hpp:42
int GetGroupSize(int g) const
int GetNSharedFaces() const
Return the number of shared faces (3D), edges (2D), vertices (1D)
Definition: pmesh.cpp:2030
int BaseGeom
Definition: mesh.hpp:59
void GetBoundingBox(Vector &min, Vector &max, int ref=2)
Definition: mesh.cpp:108
Array< int > sface_lface
Definition: pmesh.hpp:55
void SetDims(int rows, int nnz)
Definition: table.cpp:142
const int * GetGroup(int g) const
void Copy(Array &copy) const
Create a copy of the current array.
Definition: array.hpp:190
RefinedGeometry * Refine(int Geom, int Times, int ETimes=1)
Definition: geom.cpp:803
T * GetData()
Returns the data.
Definition: array.hpp:115
void SaveAsOne(std::ostream &out=mfem::out)
Merge the local grid functions.
Definition: pgridfunc.cpp:413
virtual void LocalRefinement(const Array< int > &marked_el, int type=3)
This function is not public anymore. Use GeneralRefinement instead.
Definition: pmesh.cpp:2115
Data type dense matrix using column-major storage.
Definition: densemat.hpp:23
GridFunction * Nodes
Definition: mesh.hpp:151
ElementTransformation * GetGhostFaceTransformation(FaceElementTransformations *FETr, int face_type, int face_geom)
Definition: pmesh.cpp:1914
int NumOfElements
Definition: mesh.hpp:56
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
Definition: table.cpp:189
const FiniteElement * GetTraceElement(int i, int geom_type) const
Return the trace element from element &#39;i&#39; to the given &#39;geom_type&#39;.
Definition: fespace.cpp:1625
IntegrationPointTransformation Loc2
Definition: eltrans.hpp:348
int GetBdrElementEdgeIndex(int i) const
Definition: mesh.cpp:3997
void GetCharacteristics(double &h_min, double &h_max, double &kappa_min, double &kappa_max)
Definition: pmesh.cpp:4370
int GetNE() const
Returns number of elements.
Definition: mesh.hpp:618
void SynchronizeDerefinementData(Array< Type > &elem_data, const Table &deref_table)
Definition: pncmesh.cpp:1404
const Element * GetFace(int i) const
Definition: mesh.hpp:684
virtual void SetVertices(const int *ind)
Set the indices the element according to the input.
Definition: element.cpp:17
virtual void OnMeshUpdated(Mesh *mesh)
Definition: pncmesh.cpp:156
Abstract parallel finite element space.
Definition: pfespace.hpp:28
bool have_face_nbr_data
Definition: pmesh.hpp:130
const FiniteElement * GetFE() const
Definition: eltrans.hpp:299
Array< int > face_nbr_vertices_offset
Definition: pmesh.hpp:133
std::vector< MeshId > conforming
Definition: ncmesh.hpp:171
Data type for vertex.
Definition: vertex.hpp:21
Array< int > RefEdges
Definition: geom.hpp:212
Array< int > face_nbr_group
Definition: pmesh.hpp:131
static int GetQuadOrientation(const int *base, const int *test)
Returns the orientation of &quot;test&quot; relative to &quot;base&quot;.
Definition: mesh.cpp:3548
Data type quadrilateral element.
void GetVertices(Vector &vert_coord) const
Definition: mesh.cpp:5351
int BaseBdrGeom
Definition: mesh.hpp:59
The inverse transformation of a given ElementTransformation.
Definition: eltrans.hpp:108
ElementTransformation * Elem2
Definition: eltrans.hpp:347
int GetFaceElementType(int Face) const
Definition: mesh.cpp:784
double * GetData() const
Return a pointer to the beginning of the Vector data.
Definition: vector.hpp:129
virtual void MarkTetMeshForRefinement(DSTable &v_to_v)
Definition: pmesh.cpp:1077
int Size_of_connections() const
Definition: table.hpp:98
Array< Element * > faces
Definition: mesh.hpp:75
const IntegrationRule * GetVertices(int GeomType)
Return an IntegrationRule consisting of all vertices of the given Geometry::Type, GeomType...
Definition: geom.cpp:188
const NCList & GetSharedEdges()
Definition: pncmesh.hpp:112
void GetVertexToVertexTable(DSTable &) const
Definition: mesh.cpp:4108
Array< int > sedge_ledge
Definition: pmesh.hpp:54
void RedRefinement(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle)
Definition: mesh.hpp:241
Operation last_operation
Definition: mesh.hpp:185
void skip_comment_lines(std::istream &is, const char comment_char)
Definition: text.hpp:27
int GetGeometryType() const
Definition: element.hpp:47
void DeleteAll()
Delete whole array.
Definition: array.hpp:709
void AddConnections(int r, const int *c, int nc)
Definition: table.cpp:106
void InitRefinementTransforms()
Definition: mesh.cpp:6831
IsoparametricTransformation FaceTransformation
Definition: mesh.hpp:142
const NCList & GetSharedList(int entity)
Helper to get shared vertices/edges/faces (&#39;entity&#39; == 0/1/2 resp.).
Definition: pncmesh.hpp:133
Array< NCFaceInfo > nc_faces_info
Definition: mesh.hpp:130
bool IAmMaster(int g) const
bool WantSkipSharedMaster(const NCMesh::Master &master) const
Definition: pmesh.cpp:3415
A parallel extension of the NCMesh class.
Definition: pncmesh.hpp:61
void GetSharedEdgeDofs(int group, int ei, Array< int > &dofs) const
Definition: pfespace.cpp:398
Element * NewElement(int geom)
Definition: mesh.cpp:2530
Table * el_to_face
Definition: mesh.hpp:133
FaceElementTransformations FaceElemTr
Definition: mesh.hpp:143
ParNCMesh * pncmesh
Definition: pmesh.hpp:140
int GroupVertex(int group, int i)
Definition: pmesh.hpp:149
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition: mesh.cpp:3374
virtual int FindPoints(DenseMatrix &point_mat, Array< int > &elem_ids, Array< IntegrationPoint > &ips, bool warn=true, InverseElementTransformation *inv_trans=NULL)
Find the ids of the elements that contain the given points, and their corresponding reference coordin...
Definition: pmesh.cpp:4558
void GetFaceNbrElementVDofs(int i, Array< int > &vdofs) const
Definition: pfespace.cpp:974
void ExchangeFaceNbrData()
Definition: pmesh.cpp:1378
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
Definition: gridfunc.cpp:2349
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element&#39;s vertices.
Definition: segment.cpp:40
void GetElementJacobian(int i, DenseMatrix &J)
Definition: mesh.cpp:56
Geometry Geometries
Definition: geom.cpp:760
void Rebalance()
Load balance the mesh. NC meshes only.
Definition: pmesh.cpp:2746
void GetVertexDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:1519
bool Nonconforming() const
Definition: mesh.hpp:1014
Communicator performing operations within groups defined by a GroupTopology with arbitrary-size data ...
const FiniteElement * GetFaceNbrFE(int i) const
Definition: pfespace.cpp:1008
void GetSharedFaceDofs(int group, int fi, Array< int > &dofs) const
Definition: pfespace.cpp:421
Array< int > face_nbr_elements_offset
Definition: pmesh.hpp:132
void GetEdgeOrdering(DSTable &v_to_v, Array< int > &order)
Definition: mesh.cpp:1404
MPI_Comm MyComm
Definition: pmesh.hpp:41
Symmetric 3D Table.
Definition: stable3d.hpp:28
void GetBoundingBox(Vector &p_min, Vector &p_max, int ref=2)
Definition: pmesh.cpp:4354
const Table & GetDerefinementTable()
Definition: ncmesh.cpp:1258
DenseTensor point_matrices
matrices for IsoparametricTransformation
Definition: ncmesh.hpp:54
Array< Element * > shared_edges
Definition: pmesh.hpp:44
int Append(const T &el)
Append element to array, resize if necessary.
Definition: array.hpp:614
virtual void NonconformingRefinement(const Array< Refinement > &refinements, int nc_limit=0)
This function is not public anymore. Use GeneralRefinement instead.
Definition: pmesh.cpp:2646
IntegrationPointTransformation Loc1
Definition: eltrans.hpp:348
int GetSharedFace(int sface) const
Return the local face index for the given shared face.
Definition: pmesh.cpp:2049
int GetNumNeighbors() const
void Clear()
Definition: table.cpp:373
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
Definition: error.cpp:146
void PrintAsOne(std::ostream &out=mfem::out)
Definition: pmesh.cpp:3556
void Finalize()
Allocate internal buffers after the GroupLDofTable is defined.
void GetFaceTransformation(int i, IsoparametricTransformation *FTr)
Returns the transformation defining the given face element in a user-defined variable.
Definition: mesh.cpp:391
void CreateRefinementFlag(int refinement_edges[2], int type, int flag=0)
Definition: tetrahedron.cpp:59
std::vector< Master > masters
Definition: ncmesh.hpp:172
static const int NumVerts[NumGeom]
Definition: geom.hpp:40
static FiniteElement * GetTransformationFEforElementType(int)
Definition: mesh.cpp:263
void AddConnection(int r, int c)
Definition: table.hpp:80
STable3D * GetElementToFaceTable(int ret_ftbl=0)
Definition: mesh.cpp:4466
FaceElementTransformations * GetSharedFaceTransformations(int sf, bool fill2=true)
Definition: pmesh.cpp:1945
static void Rotate3(int &, int &, int &)
Definition: mesh.hpp:1184
int MeshGenerator()
Get the mesh generator/type.
Definition: mesh.hpp:611
Table send_face_nbr_vertices
Definition: pmesh.hpp:138
int GetFaceSplittings(Element *face, const DSTable &v_to_v, int *middle)
Return a number(0-4) identifying how the given face has been split.
Definition: pmesh.cpp:1225
T Max() const
Find the maximal element in the array, using the comparison operator &lt; for class T.
Definition: array.cpp:109
int InitialPartition(int index) const
Helper to get the partitioning when the serial mesh gets split initially.
Definition: pncmesh.hpp:307
const int * GetDofMap(int GeomType) const
Get the Cartesian to local H1 dof map.
Definition: fe_coll.cpp:1655
const IntegrationRule & GetNodes() const
Definition: fe.hpp:270
int Insert(IntegerSet &s)
Definition: sets.cpp:82
virtual void Print(std::ostream &out=mfem::out) const
Definition: pmesh.cpp:3428
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
Definition: array.hpp:146
Array< Embedding > embeddings
fine element positions in their parents
Definition: ncmesh.hpp:55
void Transpose(const Table &A, Table &At, int _ncols_A)
Transpose a Table.
Definition: table.cpp:418
GeometryRefiner GlobGeometryRefiner
Definition: geom.cpp:1202
Array< Element * > shared_faces
Definition: pmesh.hpp:45
int GetAttribute() const
Return element&#39;s attribute.
Definition: element.hpp:50
int GetElementToEdgeTable(Table &, Array< int > &)
Definition: mesh.cpp:4133
Data type triangle element.
Definition: triangle.hpp:23
int GetElementType(int i) const
Returns the type of element i.
Definition: mesh.cpp:4029
void MarkCoarseLevel()
Definition: ncmesh.cpp:2834
const Element * GetElement(int i) const
Definition: mesh.hpp:676
IntegrationRule RefPts
Definition: geom.hpp:211
int GroupNVertices(int group)
Definition: pmesh.hpp:145
virtual void QuadUniformRefinement()
Refine quadrilateral mesh.
Definition: pmesh.cpp:2966
void GetLocalFaceTransformation(int face_type, int elem_type, IsoparametricTransformation &Transf, int info)
A helper method that constructs a transformation from the reference space of a face to the reference ...
Definition: mesh.cpp:624
IsoparametricTransformation Transformation2
Definition: mesh.hpp:141
int GetVDim() const
Returns vector dimension.
Definition: fespace.hpp:242
int Size() const
Returns the number of TYPE I elements.
Definition: table.hpp:92
FiniteElementSpace * FESpace()
Definition: gridfunc.hpp:337
virtual void ReorientTetMesh()
Definition: mesh.cpp:4539
virtual void HexUniformRefinement()
Refine a hexahedral mesh.
Definition: pmesh.cpp:3053
int NumOfBdrElements
Definition: mesh.hpp:56
Table * el_to_edge
Definition: mesh.hpp:132
void Rebalance()
Definition: pncmesh.cpp:1542
int slaves_end
slave faces
Definition: ncmesh.hpp:148
Data type tetrahedron element.
Definition: tetrahedron.hpp:22
Vector & FaceNbrData()
Definition: pgridfunc.hpp:178
int CheckBdrElementOrientation(bool fix_it=true)
Check the orientation of the boundary elements.
Definition: mesh.cpp:3596
int SpaceDimension() const
Definition: mesh.hpp:646
void GetBdrElementFace(int i, int *, int *) const
Return the index and the orientation of the face of bdr element i. (3D)
Definition: mesh.cpp:3952
void Save(std::ostream &out) const
Save the data in a stream.
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition: mesh.hpp:174
void RefineGroups(const DSTable &v_to_v, int *middle)
Update the groups after tet refinement.
Definition: pmesh.cpp:2779
virtual bool NonconformingDerefinement(Array< double > &elem_error, double threshold, int nc_limit=0, int op=1)
NC version of GeneralDerefinement.
Definition: pmesh.cpp:2698
Array< Vertex > face_nbr_vertices
Definition: pmesh.hpp:135
std::vector< Slave > slaves
Definition: ncmesh.hpp:173
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition: fespace.hpp:66
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition: fe.hpp:217
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
Definition: globals.hpp:69
void ApplyLocalSlaveTransformation(IsoparametricTransformation &transf, const FaceInfo &fi)
Definition: mesh.cpp:727
static void PrintElement(const Element *, std::ostream &)
Definition: mesh.cpp:2592
int GetNeighborRank(int i) const
void AddAColumnInRow(int r)
Definition: table.hpp:77
void SetSize(int nsize)
Change logical size of the array, keep existing entries.
Definition: array.hpp:569
virtual long ReduceInt(int value) const
Utility function: sum integers from all processors (Allreduce).
Definition: pmesh.cpp:4487
void Transform(const IntegrationPoint &, IntegrationPoint &)
Definition: eltrans.cpp:515
bool IsSlaveFace(const FaceInfo &fi) const
Definition: mesh.cpp:722
Array< Vertex > vertices
Definition: mesh.hpp:73
virtual void QuadUniformRefinement()
Refine quadrilateral mesh.
Definition: mesh.cpp:5500
virtual void HexUniformRefinement()
Refine hexahedral mesh.
Definition: mesh.cpp:5602
void Swap(Mesh &other, bool non_geometry=false)
Definition: mesh.cpp:6233
Table & GroupLDofTable()
Fill-in the returned Table reference to initialize the GroupCommunicator then call Finalize()...
Array< Element * > elements
Definition: mesh.hpp:68
double GetLength(int i, int j) const
Return the length of the segment from node i to node j.
Definition: mesh.cpp:4071
virtual void Update()
Transform by the Space UpdateMatrix (e.g., on Mesh change).
Definition: gridfunc.cpp:147
void ShiftUpI()
Definition: table.cpp:117
int meshgen
Definition: mesh.hpp:61
int GetElementBaseGeometry(int i=0) const
Definition: mesh.hpp:688
static FiniteElementCollection * New(const char *name)
Factory method: return a newly allocated FiniteElementCollection according to the given name...
Definition: fe_coll.cpp:44
void GetFaceNbrElementTransformation(int i, IsoparametricTransformation *ElTr)
Definition: pmesh.cpp:1305
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition: mesh.hpp:176
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition: mesh.hpp:615
Array< int > be_to_edge
Definition: mesh.hpp:135
virtual const char * Name() const
Definition: fe_coll.hpp:50
virtual void Refine(const Array< Refinement > &refinements)
Definition: pncmesh.cpp:1142
Element * ReadElementWithoutAttr(std::istream &)
Definition: mesh.cpp:2550
void GroupFace(int group, int i, int &face, int &o)
Definition: pmesh.cpp:1060
void GetElementTransformation(int i, IsoparametricTransformation *ElTr)
Definition: mesh.cpp:279
Table group_sedge
Definition: pmesh.hpp:49
void ExchangeFaceNbrNodes()
Definition: pmesh.cpp:1781
void Finalize(bool refine=false, bool fix_orientation=false)
Finalize the construction of a general Mesh.
Definition: mesh.cpp:1868
static const int Orient[NumOrient][NumVert]
Definition: geom.hpp:165
A set of integers.
Definition: sets.hpp:23
void SetIJ(int *newI, int *newJ, int newsize=-1)
Definition: table.cpp:206
void MakeJ()
Definition: table.cpp:94
Table group_svert
Shared objects in each group.
Definition: pmesh.hpp:48
int GroupNFaces(int group)
Definition: pmesh.hpp:147
virtual int DofForGeometry(int GeomType) const
Definition: fe_coll.hpp:95
void SetFE(const FiniteElement *FE)
Definition: eltrans.hpp:298
long sequence
Definition: mesh.hpp:66
IsoparametricTransformation Transf
Definition: eltrans.hpp:338
bool IsGhost(int entity, int index) const
Return true if the specified vertex/edge/face is a ghost.
Definition: pncmesh.hpp:188
ElementTransformation * Elem1
Definition: eltrans.hpp:347
double CalcSingularvalue(const int i) const
Return the i-th singular value (decreasing order) of NxN matrix, N=1,2,3.
Definition: densemat.cpp:1758
void GetVectorValues(ElementTransformation &T, const IntegrationRule &ir, DenseMatrix &vals) const
Definition: gridfunc.cpp:517
Array< FaceInfo > faces_info
Definition: mesh.hpp:129
virtual int GetNVertices() const =0
void SetAttribute(const int attr)
Set element&#39;s attribute.
Definition: element.hpp:53
STable3D * GetFacesTable()
Definition: mesh.cpp:4431
NCMesh * ncmesh
Optional non-conforming mesh extension.
Definition: mesh.hpp:177
static void PrintElementWithoutAttr(const Element *, std::ostream &)
Definition: mesh.cpp:2568
int Dim
Definition: mesh.hpp:53
virtual void CheckDerefinementNCLevel(const Table &deref_table, Array< int > &level_ok, int max_nc_level)
Definition: pncmesh.cpp:1484
int GetEdgeSplittings(Element *edge, const DSTable &v_to_v, int *middle)
Return a number(0-1) identifying how the given edge has been split.
Definition: pmesh.cpp:1203
int GetNEdges() const
Return the number of edges.
Definition: mesh.hpp:624
virtual void PrintXG(std::ostream &out=mfem::out) const
Definition: pmesh.cpp:3220
void GetMarkedFace(const int face, int *fv)
void GroupEdge(int group, int i, int &edge, int &o)
Definition: pmesh.cpp:1052
int GetNFaces() const
Return the number of faces in a 3D mesh.
Definition: mesh.hpp:627
virtual int FindPoints(DenseMatrix &point_mat, Array< int > &elem_ids, Array< IntegrationPoint > &ips, bool warn=true, InverseElementTransformation *inv_trans=NULL)
Find the ids of the elements that contain the given points, and their corresponding reference coordin...
Definition: mesh.cpp:8575
double kappa
Definition: ex3.cpp:46
Vector data type.
Definition: vector.hpp:48
const FiniteElementCollection * FEColl() const
Definition: fespace.hpp:267
virtual void Transform(const IntegrationPoint &, Vector &)=0
void GetNodes(Vector &node_coord) const
Definition: mesh.cpp:5422
int GetFaceBaseGeometry(int i) const
Definition: mesh.cpp:3975
void AverageVertices(int *indexes, int n, int result)
Definition: mesh.cpp:5470
void GenerateOffsets(int N, HYPRE_Int loc_sizes[], Array< HYPRE_Int > *offsets[]) const
Definition: pmesh.cpp:1262
int NumberOfEntries() const
Definition: table.hpp:234
static int GetTriOrientation(const int *base, const int *test)
Returns the orientation of &quot;test&quot; relative to &quot;base&quot;.
Definition: mesh.cpp:3500
int * GetI()
Definition: table.hpp:113
Arbitrary order H1-conforming (continuous) finite elements.
Definition: fe_coll.hpp:79
Array< int > svert_lvert
Shared to local index mapping.
Definition: pmesh.hpp:53
void GenerateFaces()
Definition: mesh.cpp:4315
const NCList & GetSharedFaces()
Definition: pncmesh.hpp:123
int MyRank
Definition: pmesh.hpp:42
int spaceDim
Definition: mesh.hpp:54
const NCList & GetEdgeList()
Return the current list of conforming and nonconforming edges.
Definition: ncmesh.hpp:195
void ParseRefinementFlag(int refinement_edges[2], int &type, int &flag)
Definition: tetrahedron.cpp:43
int RowSize(int i) const
Definition: table.hpp:108
Class for parallel grid function.
Definition: pgridfunc.hpp:32
friend class ParNCMesh
Definition: mesh.hpp:48
Table group_sface
Definition: pmesh.hpp:50
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition: densemat.hpp:86
Table send_face_nbr_elements
Definition: pmesh.hpp:137
virtual void PrintInfo(std::ostream &out=mfem::out)
Print various parallel mesh stats.
Definition: pmesh.cpp:4383
List of integer sets.
Definition: sets.hpp:54
int NumOfVertices
Definition: mesh.hpp:56
Table * GetFaceToAllElementTable() const
Definition: pmesh.cpp:1856
void DeleteFaceNbrData()
Definition: pmesh.cpp:1357
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition: globals.hpp:64
void InitFromNCMesh(const NCMesh &ncmesh)
Initialize vertices/elements/boundary/tables from a nonconforming mesh.
Definition: mesh.cpp:6175
GroupTopology gtopo
Definition: pmesh.hpp:127
void Bisection(int i, const DSTable &, int *, int *, int *)
Definition: mesh.cpp:6498
void ParPrint(std::ostream &out) const
Save the mesh in a parallel mesh format.
Definition: pmesh.cpp:4494
Class for parallel meshes.
Definition: pmesh.hpp:32
Abstract data type element.
Definition: element.hpp:27
int GetAttribute(int i) const
Return the attribute of element i.
Definition: mesh.hpp:862
int GetFaceNbrRank(int fn) const
Definition: pmesh.cpp:1839
const Table & ElementToEdgeTable() const
Definition: mesh.cpp:4217
Data type line segment element.
Definition: segment.hpp:22
void GenerateNCFaceInfo()
Definition: mesh.cpp:4384
Array< int > RefGeoms
Definition: geom.hpp:212
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
Definition: mesh.hpp:695
virtual void LimitNCLevel(int max_nc_level)
Parallel version of NCMesh::LimitNCLevel.
Definition: pncmesh.cpp:1214
Array< int > attributes
A list of all unique element attributes used by the Mesh.
Definition: mesh.hpp:172
Table * GetVertexToElementTable()
The returned Table must be destroyed by the caller.
Definition: mesh.cpp:3845
const Element * GetBdrElement(int i) const
Definition: mesh.hpp:680
static const int Orient[NumOrient][NumVert]
Definition: geom.hpp:144
void Load(std::istream &in)
Load the data from a stream.
virtual int GetType() const =0
Returns element&#39;s type.
void UpdateNodes()
Update the nodes of a curved mesh after refinement.
Definition: mesh.cpp:5491
Defines the position of a fine element within a coarse element.
Definition: ncmesh.hpp:43
int GroupNEdges(int group)
Definition: pmesh.hpp:146
void GreenRefinement(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle)
Definition: mesh.hpp:247
void Printer(std::ostream &out=mfem::out, std::string section_delimiter="") const
Definition: mesh.cpp:7075
ParFiniteElementSpace * ParFESpace() const
Definition: pgridfunc.hpp:85
virtual void NURBSUniformRefinement()
Refine NURBS mesh.
Definition: pmesh.cpp:3212
int NumOfFaces
Definition: mesh.hpp:57