MFEM  v3.1
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 <iostream>
21 using namespace std;
22 
23 namespace mfem
24 {
25 
26 ParMesh::ParMesh(const ParMesh &pmesh, bool copy_nodes)
27  : Mesh(pmesh, false),
28  group_svert(pmesh.group_svert),
29  group_sedge(pmesh.group_sedge),
30  group_sface(pmesh.group_sface),
31  gtopo(pmesh.gtopo)
32 {
33  MyComm = pmesh.MyComm;
34  NRanks = pmesh.NRanks;
35  MyRank = pmesh.MyRank;
36 
37  // Duplicate the shared_edges
38  shared_edges.SetSize(pmesh.shared_edges.Size());
39  for (int i = 0; i < shared_edges.Size(); i++)
40  {
41  shared_edges[i] = pmesh.shared_edges[i]->Duplicate(this);
42  }
43 
44  // Duplicate the shared_faces
45  shared_faces.SetSize(pmesh.shared_faces.Size());
46  for (int i = 0; i < shared_faces.Size(); i++)
47  {
48  shared_faces[i] = pmesh.shared_faces[i]->Duplicate(this);
49  }
50 
51  // Copy the shared-to-local index Arrays
52  pmesh.svert_lvert.Copy(svert_lvert);
53  pmesh.sedge_ledge.Copy(sedge_ledge);
54  pmesh.sface_lface.Copy(sface_lface);
55 
56  // Do not copy face-neighbor data (can be generated if needed)
57  have_face_nbr_data = false;
58 
59  // Copy the Nodes as a ParGridFunction, including the FiniteElementCollection
60  // and the FiniteElementSpace (as a ParFiniteElementSpace)
61  if (pmesh.Nodes && copy_nodes)
62  {
63  FiniteElementSpace *fes = pmesh.Nodes->FESpace();
64  const FiniteElementCollection *fec = fes->FEColl();
65  FiniteElementCollection *fec_copy =
67  ParFiniteElementSpace *pfes_copy =
68  new ParFiniteElementSpace(this, fec_copy, fes->GetVDim(),
69  fes->GetOrdering());
70  Nodes = new ParGridFunction(pfes_copy);
71  Nodes->MakeOwner(fec_copy);
72  *Nodes = *pmesh.Nodes;
73  own_nodes = 1;
74  }
75 }
76 
77 ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
78  int part_method)
79  : gtopo(comm)
80 {
81  int i, j;
82  int *partitioning;
83  Array<bool> activeBdrElem;
84 
85  MyComm = comm;
86  MPI_Comm_size(MyComm, &NRanks);
87  MPI_Comm_rank(MyComm, &MyRank);
88 
89  Dim = mesh.Dim;
90  spaceDim = mesh.spaceDim;
91 
92  if (mesh.ncmesh)
93  {
94  pncmesh = new ParNCMesh(comm, *mesh.ncmesh);
95 
96  // save the element partitioning before Prune()
97  int* partition = new int[mesh.GetNE()];
98  for (int i = 0; i < mesh.GetNE(); i++)
99  {
100  partition[i] = pncmesh->InitialPartition(i);
101  }
102 
103  pncmesh->Prune();
104 
105  Mesh::Init();
108  spaceDim = mesh.spaceDim;
109  pncmesh->OnMeshUpdated(this);
110 
111  meshgen = mesh.MeshGenerator();
112  ncmesh = pncmesh;
113 
114  mesh.attributes.Copy(attributes);
116 
117  if (mesh.GetNodes())
118  {
119  Nodes = new ParGridFunction(this, mesh.GetNodes(), partition);
120  own_nodes = 1;
121  }
122  delete [] partition;
123  have_face_nbr_data = false;
124  return;
125  }
126  else
127  {
128  ncmesh = pncmesh = NULL;
129  }
130 
131  if (partitioning_)
132  {
133  partitioning = partitioning_;
134  }
135  else
136  {
137  partitioning = mesh.GeneratePartitioning(NRanks, part_method);
138  }
139 
140  // re-enumerate the partitions to better map to actual processor
141  // interconnect topology !?
142 
143  Array<int> vert;
144  Array<int> vert_global_local(mesh.GetNV());
145  int vert_counter, element_counter, bdrelem_counter;
146 
147  // build vert_global_local
148  vert_global_local = -1;
149 
150  element_counter = 0;
151  vert_counter = 0;
152  for (i = 0; i < mesh.GetNE(); i++)
153  if (partitioning[i] == MyRank)
154  {
155  mesh.GetElementVertices(i, vert);
156  element_counter++;
157  for (j = 0; j < vert.Size(); j++)
158  if (vert_global_local[vert[j]] < 0)
159  {
160  vert_global_local[vert[j]] = vert_counter++;
161  }
162  }
163 
164  NumOfVertices = vert_counter;
165  NumOfElements = element_counter;
166  vertices.SetSize(NumOfVertices);
167 
168  // re-enumerate the local vertices to preserve the global ordering
169  for (i = vert_counter = 0; i < vert_global_local.Size(); i++)
170  if (vert_global_local[i] >= 0)
171  {
172  vert_global_local[i] = vert_counter++;
173  }
174 
175  // determine vertices
176  for (i = 0; i < vert_global_local.Size(); i++)
177  if (vert_global_local[i] >= 0)
178  {
179  vertices[vert_global_local[i]].SetCoords(mesh.GetVertex(i));
180  }
181 
182  // determine elements
183  element_counter = 0;
184  elements.SetSize(NumOfElements);
185  for (i = 0; i < mesh.GetNE(); i++)
186  if (partitioning[i] == MyRank)
187  {
188  elements[element_counter] = mesh.GetElement(i)->Duplicate(this);
189  int *v = elements[element_counter]->GetVertices();
190  int nv = elements[element_counter]->GetNVertices();
191  for (j = 0; j < nv; j++)
192  {
193  v[j] = vert_global_local[v[j]];
194  }
195  element_counter++;
196  }
197 
198  Table *edge_element = NULL;
199  if (mesh.NURBSext)
200  {
201  activeBdrElem.SetSize(mesh.GetNBE());
202  activeBdrElem = false;
203  }
204  // build boundary elements
205  if (Dim == 3)
206  {
207  NumOfBdrElements = 0;
208  for (i = 0; i < mesh.GetNBE(); i++)
209  {
210  int face, o, el1, el2;
211  mesh.GetBdrElementFace(i, &face, &o);
212  mesh.GetFaceElements(face, &el1, &el2);
213  if (partitioning[(o % 2 == 0 || el2 < 0) ? el1 : el2] == MyRank)
214  {
216  if (mesh.NURBSext)
217  {
218  activeBdrElem[i] = true;
219  }
220  }
221  }
222 
223  bdrelem_counter = 0;
224  boundary.SetSize(NumOfBdrElements);
225  for (i = 0; i < mesh.GetNBE(); i++)
226  {
227  int face, o, el1, el2;
228  mesh.GetBdrElementFace(i, &face, &o);
229  mesh.GetFaceElements(face, &el1, &el2);
230  if (partitioning[(o % 2 == 0 || el2 < 0) ? el1 : el2] == MyRank)
231  {
232  boundary[bdrelem_counter] = mesh.GetBdrElement(i)->Duplicate(this);
233  int *v = boundary[bdrelem_counter]->GetVertices();
234  int nv = boundary[bdrelem_counter]->GetNVertices();
235  for (j = 0; j < nv; j++)
236  {
237  v[j] = vert_global_local[v[j]];
238  }
239  bdrelem_counter++;
240  }
241  }
242  }
243  else if (Dim == 2)
244  {
245  edge_element = new Table;
246  Transpose(mesh.ElementToEdgeTable(), *edge_element, mesh.GetNEdges());
247 
248  NumOfBdrElements = 0;
249  for (i = 0; i < mesh.GetNBE(); i++)
250  {
251  int edge = mesh.GetBdrElementEdgeIndex(i);
252  int el1 = edge_element->GetRow(edge)[0];
253  if (partitioning[el1] == MyRank)
254  {
255  NumOfBdrElements++;
256  if (mesh.NURBSext)
257  {
258  activeBdrElem[i] = true;
259  }
260  }
261  }
262 
263  bdrelem_counter = 0;
264  boundary.SetSize(NumOfBdrElements);
265  for (i = 0; i < mesh.GetNBE(); i++)
266  {
267  int edge = mesh.GetBdrElementEdgeIndex(i);
268  int el1 = edge_element->GetRow(edge)[0];
269  if (partitioning[el1] == MyRank)
270  {
271  boundary[bdrelem_counter] = mesh.GetBdrElement(i)->Duplicate(this);
272  int *v = boundary[bdrelem_counter]->GetVertices();
273  int nv = boundary[bdrelem_counter]->GetNVertices();
274  for (j = 0; j < nv; j++)
275  {
276  v[j] = vert_global_local[v[j]];
277  }
278  bdrelem_counter++;
279  }
280  }
281  }
282  else if (Dim == 1)
283  {
284  NumOfBdrElements = 0;
285  for (i = 0; i < mesh.GetNBE(); i++)
286  {
287  int vert = mesh.boundary[i]->GetVertices()[0];
288  int el1, el2;
289  mesh.GetFaceElements(vert, &el1, &el2);
290  if (partitioning[el1] == MyRank)
291  {
293  }
294  }
295 
296  bdrelem_counter = 0;
297  boundary.SetSize(NumOfBdrElements);
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  {
305  boundary[bdrelem_counter] = mesh.GetBdrElement(i)->Duplicate(this);
306  int *v = boundary[bdrelem_counter]->GetVertices();
307  v[0] = vert_global_local[v[0]];
308  bdrelem_counter++;
309  }
310  }
311  }
312 
313  meshgen = mesh.MeshGenerator();
314 
315  mesh.attributes.Copy(attributes);
317 
318  // this is called by the default Mesh constructor
319  // InitTables();
320 
321  if (Dim > 1)
322  {
323  el_to_edge = new Table;
325  }
326  else
327  {
328  NumOfEdges = 0;
329  }
330 
331  STable3D *faces_tbl = NULL;
332  if (Dim == 3)
333  {
334  faces_tbl = GetElementToFaceTable(1);
335  }
336  else
337  {
338  NumOfFaces = 0;
339  }
340  GenerateFaces();
341 
342  c_el_to_edge = NULL;
343 
344  ListOfIntegerSets groups;
345  IntegerSet group;
346 
347  // the first group is the local one
348  group.Recreate(1, &MyRank);
349  groups.Insert(group);
350 
351 #ifdef MFEM_DEBUG
352  if (Dim < 3 && mesh.GetNFaces() != 0)
353  {
354  cerr << "ParMesh::ParMesh (proc " << MyRank << ") : "
355  "(Dim < 3 && mesh.GetNFaces() != 0) is true!" << endl;
356  mfem_error();
357  }
358 #endif
359  // determine shared faces
360  int sface_counter = 0;
361  Array<int> face_group(mesh.GetNFaces());
362  for (i = 0; i < face_group.Size(); i++)
363  {
364  int el[2];
365  face_group[i] = -1;
366  mesh.GetFaceElements(i, &el[0], &el[1]);
367  if (el[1] >= 0)
368  {
369  el[0] = partitioning[el[0]];
370  el[1] = partitioning[el[1]];
371  if ((el[0] == MyRank && el[1] != MyRank) ||
372  (el[0] != MyRank && el[1] == MyRank))
373  {
374  group.Recreate(2, el);
375  face_group[i] = groups.Insert(group) - 1;
376  sface_counter++;
377  }
378  }
379  }
380 
381  // determine shared edges
382  int sedge_counter = 0;
383  if (!edge_element)
384  {
385  edge_element = new Table;
386  if (Dim == 1)
387  {
388  edge_element->SetDims(0,0);
389  }
390  else
391  {
392  Transpose(mesh.ElementToEdgeTable(), *edge_element, mesh.GetNEdges());
393  }
394  }
395  for (i = 0; i < edge_element->Size(); i++)
396  {
397  int me = 0, others = 0;
398  for (j = edge_element->GetI()[i]; j < edge_element->GetI()[i+1]; j++)
399  {
400  edge_element->GetJ()[j] = partitioning[edge_element->GetJ()[j]];
401  if (edge_element->GetJ()[j] == MyRank)
402  {
403  me = 1;
404  }
405  else
406  {
407  others = 1;
408  }
409  }
410 
411  if (me && others)
412  {
413  sedge_counter++;
414  group.Recreate(edge_element->RowSize(i), edge_element->GetRow(i));
415  edge_element->GetRow(i)[0] = groups.Insert(group) - 1;
416  }
417  else
418  {
419  edge_element->GetRow(i)[0] = -1;
420  }
421  }
422 
423  // determine shared vertices
424  int svert_counter = 0;
425  Table *vert_element = mesh.GetVertexToElementTable(); // we must delete this
426 
427  for (i = 0; i < vert_element->Size(); i++)
428  {
429  int me = 0, others = 0;
430  for (j = vert_element->GetI()[i]; j < vert_element->GetI()[i+1]; j++)
431  {
432  vert_element->GetJ()[j] = partitioning[vert_element->GetJ()[j]];
433  if (vert_element->GetJ()[j] == MyRank)
434  {
435  me = 1;
436  }
437  else
438  {
439  others = 1;
440  }
441  }
442 
443  if (me && others)
444  {
445  svert_counter++;
446  group.Recreate(vert_element->RowSize(i), vert_element->GetRow(i));
447  vert_element->GetI()[i] = groups.Insert(group) - 1;
448  }
449  else
450  {
451  vert_element->GetI()[i] = -1;
452  }
453  }
454 
455  // build group_sface
456  group_sface.MakeI(groups.Size()-1);
457 
458  for (i = 0; i < face_group.Size(); i++)
459  if (face_group[i] >= 0)
460  {
461  group_sface.AddAColumnInRow(face_group[i]);
462  }
463 
464  group_sface.MakeJ();
465 
466  sface_counter = 0;
467  for (i = 0; i < face_group.Size(); i++)
468  if (face_group[i] >= 0)
469  {
470  group_sface.AddConnection(face_group[i], sface_counter++);
471  }
472 
473  group_sface.ShiftUpI();
474 
475  // build group_sedge
476  group_sedge.MakeI(groups.Size()-1);
477 
478  for (i = 0; i < edge_element->Size(); i++)
479  if (edge_element->GetRow(i)[0] >= 0)
480  {
481  group_sedge.AddAColumnInRow(edge_element->GetRow(i)[0]);
482  }
483 
484  group_sedge.MakeJ();
485 
486  sedge_counter = 0;
487  for (i = 0; i < edge_element->Size(); i++)
488  if (edge_element->GetRow(i)[0] >= 0)
489  group_sedge.AddConnection(edge_element->GetRow(i)[0],
490  sedge_counter++);
491 
492  group_sedge.ShiftUpI();
493 
494  // build group_svert
495  group_svert.MakeI(groups.Size()-1);
496 
497  for (i = 0; i < vert_element->Size(); i++)
498  if (vert_element->GetI()[i] >= 0)
499  {
500  group_svert.AddAColumnInRow(vert_element->GetI()[i]);
501  }
502 
503  group_svert.MakeJ();
504 
505  svert_counter = 0;
506  for (i = 0; i < vert_element->Size(); i++)
507  if (vert_element->GetI()[i] >= 0)
508  group_svert.AddConnection(vert_element->GetI()[i],
509  svert_counter++);
510 
511  group_svert.ShiftUpI();
512 
513  // build shared_faces and sface_lface
514  shared_faces.SetSize(sface_counter);
515  sface_lface. SetSize(sface_counter);
516 
517  if (Dim == 3)
518  {
519  sface_counter = 0;
520  for (i = 0; i < face_group.Size(); i++)
521  if (face_group[i] >= 0)
522  {
523  shared_faces[sface_counter] = mesh.GetFace(i)->Duplicate(this);
524  int *v = shared_faces[sface_counter]->GetVertices();
525  int nv = shared_faces[sface_counter]->GetNVertices();
526  for (j = 0; j < nv; j++)
527  {
528  v[j] = vert_global_local[v[j]];
529  }
530  switch (shared_faces[sface_counter]->GetType())
531  {
532  case Element::TRIANGLE:
533  sface_lface[sface_counter] = (*faces_tbl)(v[0], v[1], v[2]);
534  // mark the shared face for refinement by reorienting
535  // it according to the refinement flag in the tetradron
536  // to which this shared face belongs to.
537  {
538  int lface = sface_lface[sface_counter];
539  Tetrahedron *tet =
540  (Tetrahedron *)(elements[faces_info[lface].Elem1No]);
541  int re[2], type, flag, *tv;
542  tet->ParseRefinementFlag(re, type, flag);
543  tv = tet->GetVertices();
544  switch (faces_info[lface].Elem1Inf/64)
545  {
546  case 0:
547  switch (re[1])
548  {
549  case 1: v[0] = tv[1]; v[1] = tv[2]; v[2] = tv[3];
550  break;
551  case 4: v[0] = tv[3]; v[1] = tv[1]; v[2] = tv[2];
552  break;
553  case 5: v[0] = tv[2]; v[1] = tv[3]; v[2] = tv[1];
554  break;
555  }
556  break;
557  case 1:
558  switch (re[0])
559  {
560  case 2: v[0] = tv[2]; v[1] = tv[0]; v[2] = tv[3];
561  break;
562  case 3: v[0] = tv[0]; v[1] = tv[3]; v[2] = tv[2];
563  break;
564  case 5: v[0] = tv[3]; v[1] = tv[2]; v[2] = tv[0];
565  break;
566  }
567  break;
568  case 2:
569  v[0] = tv[0]; v[1] = tv[1]; v[2] = tv[3];
570  break;
571  case 3:
572  v[0] = tv[1]; v[1] = tv[0]; v[2] = tv[2];
573  break;
574  }
575  // flip the shared face in the processor that owns the
576  // second element (in 'mesh')
577  {
578  int gl_el1, gl_el2;
579  mesh.GetFaceElements(i, &gl_el1, &gl_el2);
580  if (MyRank == partitioning[gl_el2])
581  {
582  const int t = v[0]; v[0] = v[1]; v[1] = t;
583  }
584  }
585  }
586  break;
588  sface_lface[sface_counter] =
589  (*faces_tbl)(v[0], v[1], v[2], v[3]);
590  break;
591  }
592  sface_counter++;
593  }
594 
595  delete faces_tbl;
596  }
597 
598  // build shared_edges and sedge_ledge
599  shared_edges.SetSize(sedge_counter);
600  sedge_ledge. SetSize(sedge_counter);
601 
602  {
603  DSTable v_to_v(NumOfVertices);
604  GetVertexToVertexTable(v_to_v);
605 
606  sedge_counter = 0;
607  for (i = 0; i < edge_element->Size(); i++)
608  if (edge_element->GetRow(i)[0] >= 0)
609  {
610  mesh.GetEdgeVertices(i, vert);
611 
612  shared_edges[sedge_counter] =
613  new Segment(vert_global_local[vert[0]],
614  vert_global_local[vert[1]], 1);
615 
616  if ((sedge_ledge[sedge_counter] =
617  v_to_v(vert_global_local[vert[0]],
618  vert_global_local[vert[1]])) < 0)
619  {
620  cerr << "\n\n\n" << MyRank << ": ParMesh::ParMesh: "
621  << "ERROR in v_to_v\n\n" << endl;
622  mfem_error();
623  }
624 
625  sedge_counter++;
626  }
627  }
628 
629  delete edge_element;
630 
631  // build svert_lvert
632  svert_lvert.SetSize(svert_counter);
633 
634  svert_counter = 0;
635  for (i = 0; i < vert_element->Size(); i++)
636  if (vert_element->GetI()[i] >= 0)
637  {
638  svert_lvert[svert_counter++] = vert_global_local[i];
639  }
640 
641  delete vert_element;
642 
643  // build the group communication topology
644  gtopo.Create(groups, 822);
645 
646  if (mesh.NURBSext)
647  {
648  NURBSext = new ParNURBSExtension(comm, mesh.NURBSext, partitioning,
649  activeBdrElem);
650  }
651 
652  if (mesh.GetNodes()) // curved mesh
653  {
654  Nodes = new ParGridFunction(this, mesh.GetNodes());
655  own_nodes = 1;
656 
657  Array<int> gvdofs, lvdofs;
658  Vector lnodes;
659  element_counter = 0;
660  for (i = 0; i < mesh.GetNE(); i++)
661  if (partitioning[i] == MyRank)
662  {
663  Nodes->FESpace()->GetElementVDofs(element_counter, lvdofs);
664  mesh.GetNodes()->FESpace()->GetElementVDofs(i, gvdofs);
665  mesh.GetNodes()->GetSubVector(gvdofs, lnodes);
666  Nodes->SetSubVector(lvdofs, lnodes);
667  element_counter++;
668  }
669  }
670 
671  if (partitioning_ == NULL)
672  {
673  delete [] partitioning;
674  }
675 
676  have_face_nbr_data = false;
677 }
678 
679 ParMesh::ParMesh(const ParNCMesh &pncmesh)
680  : MyComm(pncmesh.MyComm)
681  , NRanks(pncmesh.NRanks)
682  , MyRank(pncmesh.MyRank)
683  , gtopo(MyComm)
684  , pncmesh(NULL)
685 {
686  Mesh::Init();
688  Mesh::InitFromNCMesh(pncmesh);
689  have_face_nbr_data = false;
690 }
691 
692 void ParMesh::GroupEdge(int group, int i, int &edge, int &o)
693 {
694  int sedge = group_sedge.GetJ()[group_sedge.GetI()[group-1]+i];
695  edge = sedge_ledge[sedge];
696  int *v = shared_edges[sedge]->GetVertices();
697  o = (v[0] < v[1]) ? (+1) : (-1);
698 }
699 
700 void ParMesh::GroupFace(int group, int i, int &face, int &o)
701 {
702  int sface = group_sface.GetJ()[group_sface.GetI()[group-1]+i];
703  face = sface_lface[sface];
704  // face gives the base orientation
705  if (faces[face]->GetType() == Element::TRIANGLE)
706  o = GetTriOrientation(faces[face]->GetVertices(),
707  shared_faces[sface]->GetVertices());
708  if (faces[face]->GetType() == Element::QUADRILATERAL)
709  o = GetQuadOrientation(faces[face]->GetVertices(),
710  shared_faces[sface]->GetVertices());
711 }
712 
713 // For a line segment with vertices v[0] and v[1], return a number with
714 // the following meaning:
715 // 0 - the edge was not refined
716 // 1 - the edge e was refined once by splitting v[0],v[1]
717 int ParMesh::GetEdgeSplittings(Element *edge, const DSTable &v_to_v,
718  int *middle)
719 {
720  int m, *v = edge->GetVertices();
721 
722  if ((m = v_to_v(v[0], v[1])) != -1 && middle[m] != -1)
723  {
724  return 1;
725  }
726  else
727  {
728  return 0;
729  }
730 }
731 
732 // For a triangular face with (correctly ordered) vertices v[0], v[1], v[2]
733 // return a number with the following meaning:
734 // 0 - the face was not refined
735 // 1 - the face was refined once by splitting v[0],v[1]
736 // 2 - the face was refined twice by splitting v[0],v[1] and then v[1],v[2]
737 // 3 - the face was refined twice by splitting v[0],v[1] and then v[0],v[2]
738 // 4 - the face was refined three times (as in 2+3)
739 int ParMesh::GetFaceSplittings(Element *face, const DSTable &v_to_v,
740  int *middle)
741 {
742  int m, right = 0;
743  int number_of_splittings = 0;
744  int *v = face->GetVertices();
745 
746  if ((m = v_to_v(v[0], v[1])) != -1 && middle[m] != -1)
747  {
748  number_of_splittings++;
749  if ((m = v_to_v(v[1], v[2])) != -1 && middle[m] != -1)
750  {
751  right = 1;
752  number_of_splittings++;
753  }
754  if ((m = v_to_v(v[2], v[0])) != -1 && middle[m] != -1)
755  {
756  number_of_splittings++;
757  }
758 
759  switch (number_of_splittings)
760  {
761  case 2:
762  if (right == 0)
763  {
764  number_of_splittings++;
765  }
766  break;
767  case 3:
768  number_of_splittings++;
769  break;
770  }
771  }
772 
773  return number_of_splittings;
774 }
775 
776 void ParMesh::GetFaceNbrElementTransformation(
777  int i, IsoparametricTransformation *ElTr)
778 {
779  DenseMatrix &pointmat = ElTr->GetPointMat();
780  Element *elem = face_nbr_elements[i];
781 
782  ElTr->Attribute = elem->GetAttribute();
783  ElTr->ElementNo = NumOfElements + i;
784 
785  if (Nodes == NULL)
786  {
787  const int nv = elem->GetNVertices();
788  const int *v = elem->GetVertices();
789 
790  pointmat.SetSize(spaceDim, nv);
791  for (int k = 0; k < spaceDim; k++)
792  for (int j = 0; j < nv; j++)
793  {
794  pointmat(k, j) = face_nbr_vertices[v[j]](k);
795  }
796 
797  ElTr->SetFE(GetTransformationFEforElementType(elem->GetType()));
798  }
799  else
800  {
801  Array<int> vdofs;
802  ParGridFunction *pNodes = dynamic_cast<ParGridFunction *>(Nodes);
803  if (pNodes)
804  {
805  pNodes->ParFESpace()->GetFaceNbrElementVDofs(i, vdofs);
806  int n = vdofs.Size()/spaceDim;
807  pointmat.SetSize(spaceDim, n);
808  for (int k = 0; k < spaceDim; k++)
809  for (int j = 0; j < n; j++)
810  {
811  pointmat(k,j) = (pNodes->FaceNbrData())(vdofs[n*k+j]);
812  }
813 
814  ElTr->SetFE(pNodes->ParFESpace()->GetFaceNbrFE(i));
815  }
816  else
817  mfem_error("ParMesh::GetFaceNbrElementTransformation : "
818  "Nodes are not ParGridFunction!");
819  }
820 }
821 
822 void ParMesh::DeleteFaceNbrData()
823 {
824  if (!have_face_nbr_data)
825  {
826  return;
827  }
828 
829  have_face_nbr_data = false;
833  for (int i = 0; i < face_nbr_elements.Size(); i++)
834  {
836  }
837  face_nbr_elements.DeleteAll();
838  face_nbr_vertices.DeleteAll();
841 }
842 
844 {
845  if (have_face_nbr_data)
846  {
847  return;
848  }
849 
850  Table *gr_sface;
851  int *s2l_face;
852  if (Dim == 1)
853  {
854  gr_sface = &group_svert;
855  s2l_face = svert_lvert;
856  }
857  else if (Dim == 2)
858  {
859  gr_sface = &group_sedge;
860  s2l_face = sedge_ledge;
861  }
862  else
863  {
864  gr_sface = &group_sface;
865  s2l_face = sface_lface;
866  }
867 
868  int num_face_nbrs = 0;
869  for (int g = 1; g < GetNGroups(); g++)
870  if (gr_sface->RowSize(g-1) > 0)
871  {
872  num_face_nbrs++;
873  }
874 
875  face_nbr_group.SetSize(num_face_nbrs);
876 
877  if (num_face_nbrs == 0)
878  {
879  have_face_nbr_data = true;
880  return;
881  }
882 
883  {
884  // sort face-neighbors by processor rank
885  Array<Pair<int, int> > rank_group(num_face_nbrs);
886 
887  for (int g = 1, counter = 0; g < GetNGroups(); g++)
888  if (gr_sface->RowSize(g-1) > 0)
889  {
890 #ifdef MFEM_DEBUG
891  if (gtopo.GetGroupSize(g) != 2)
892  mfem_error("ParMesh::ExchangeFaceNbrData() : "
893  "group size is not 2!");
894 #endif
895  const int *nbs = gtopo.GetGroup(g);
896  int lproc = (nbs[0]) ? nbs[0] : nbs[1];
897  rank_group[counter].one = gtopo.GetNeighborRank(lproc);
898  rank_group[counter].two = g;
899  counter++;
900  }
901 
902  SortPairs<int, int>(rank_group, rank_group.Size());
903 
904  for (int fn = 0; fn < num_face_nbrs; fn++)
905  {
906  face_nbr_group[fn] = rank_group[fn].two;
907  }
908  }
909 
910  MPI_Request *requests = new MPI_Request[2*num_face_nbrs];
911  MPI_Request *send_requests = requests;
912  MPI_Request *recv_requests = requests + num_face_nbrs;
913  MPI_Status *statuses = new MPI_Status[num_face_nbrs];
914 
915  int *nbr_data = new int[6*num_face_nbrs];
916  int *nbr_send_data = nbr_data;
917  int *nbr_recv_data = nbr_data + 3*num_face_nbrs;
918 
919  Array<int> el_marker(GetNE());
920  Array<int> vertex_marker(GetNV());
921  el_marker = -1;
922  vertex_marker = -1;
923 
924  Table send_face_nbr_elemdata, send_face_nbr_facedata;
925 
926  send_face_nbr_elements.MakeI(num_face_nbrs);
927  send_face_nbr_vertices.MakeI(num_face_nbrs);
928  send_face_nbr_elemdata.MakeI(num_face_nbrs);
929  send_face_nbr_facedata.MakeI(num_face_nbrs);
930  for (int fn = 0; fn < num_face_nbrs; fn++)
931  {
932  int nbr_group = face_nbr_group[fn];
933  int num_sfaces = gr_sface->RowSize(nbr_group-1);
934  int *sface = gr_sface->GetRow(nbr_group-1);
935  for (int i = 0; i < num_sfaces; i++)
936  {
937  int lface = s2l_face[sface[i]];
938  int el = faces_info[lface].Elem1No;
939  if (el_marker[el] != fn)
940  {
941  el_marker[el] = fn;
943 
944  const int nv = elements[el]->GetNVertices();
945  const int *v = elements[el]->GetVertices();
946  for (int j = 0; j < nv; j++)
947  if (vertex_marker[v[j]] != fn)
948  {
949  vertex_marker[v[j]] = fn;
951  }
952 
953  send_face_nbr_elemdata.AddColumnsInRow(fn, nv + 2);
954  }
955  }
956  send_face_nbr_facedata.AddColumnsInRow(fn, 2*num_sfaces);
957 
958  nbr_send_data[3*fn ] = send_face_nbr_elements.GetI()[fn];
959  nbr_send_data[3*fn+1] = send_face_nbr_vertices.GetI()[fn];
960  nbr_send_data[3*fn+2] = send_face_nbr_elemdata.GetI()[fn];
961 
962  int nbr_rank = GetFaceNbrRank(fn);
963  int tag = 0;
964 
965  MPI_Isend(&nbr_send_data[3*fn], 3, MPI_INT, nbr_rank, tag, MyComm,
966  &send_requests[fn]);
967  MPI_Irecv(&nbr_recv_data[3*fn], 3, MPI_INT, nbr_rank, tag, MyComm,
968  &recv_requests[fn]);
969  }
972  send_face_nbr_elemdata.MakeJ();
973  send_face_nbr_facedata.MakeJ();
974  el_marker = -1;
975  vertex_marker = -1;
976  for (int fn = 0; fn < num_face_nbrs; fn++)
977  {
978  int nbr_group = face_nbr_group[fn];
979  int num_sfaces = gr_sface->RowSize(nbr_group-1);
980  int *sface = gr_sface->GetRow(nbr_group-1);
981  for (int i = 0; i < num_sfaces; i++)
982  {
983  int lface = s2l_face[sface[i]];
984  int el = faces_info[lface].Elem1No;
985  if (el_marker[el] != fn)
986  {
987  el_marker[el] = fn;
989 
990  const int nv = elements[el]->GetNVertices();
991  const int *v = elements[el]->GetVertices();
992  for (int j = 0; j < nv; j++)
993  if (vertex_marker[v[j]] != fn)
994  {
995  vertex_marker[v[j]] = fn;
997  }
998 
999  send_face_nbr_elemdata.AddConnection(fn, GetAttribute(el));
1000  send_face_nbr_elemdata.AddConnection(
1001  fn, GetElementBaseGeometry(el));
1002  send_face_nbr_elemdata.AddConnections(fn, v, nv);
1003  }
1004  send_face_nbr_facedata.AddConnection(fn, el);
1005  int info = faces_info[lface].Elem1Inf;
1006  // change the orientation in info to be relative to the shared face
1007  // in 1D and 2D keep the orientation equal to 0
1008  if (Dim == 3)
1009  {
1010  Element *lf = faces[lface];
1011  const int *sf_v = shared_faces[sface[i]]->GetVertices();
1012 
1013  if (lf->GetGeometryType() == Geometry::TRIANGLE)
1014  {
1015  info += GetTriOrientation(sf_v, lf->GetVertices());
1016  }
1017  else
1018  {
1019  info += GetQuadOrientation(sf_v, lf->GetVertices());
1020  }
1021  }
1022  send_face_nbr_facedata.AddConnection(fn, info);
1023  }
1024  }
1027  send_face_nbr_elemdata.ShiftUpI();
1028  send_face_nbr_facedata.ShiftUpI();
1029 
1030  // convert the vertex indices in send_face_nbr_elemdata
1031  // convert the element indices in send_face_nbr_facedata
1032  for (int fn = 0; fn < num_face_nbrs; fn++)
1033  {
1034  int num_elems = send_face_nbr_elements.RowSize(fn);
1035  int *elems = send_face_nbr_elements.GetRow(fn);
1036  int num_verts = send_face_nbr_vertices.RowSize(fn);
1037  int *verts = send_face_nbr_vertices.GetRow(fn);
1038  int *elemdata = send_face_nbr_elemdata.GetRow(fn);
1039  int num_sfaces = send_face_nbr_facedata.RowSize(fn)/2;
1040  int *facedata = send_face_nbr_facedata.GetRow(fn);
1041 
1042  for (int i = 0; i < num_verts; i++)
1043  {
1044  vertex_marker[verts[i]] = i;
1045  }
1046 
1047  for (int el = 0; el < num_elems; el++)
1048  {
1049  const int nv = elements[el]->GetNVertices();
1050  elemdata += 2; // skip the attribute and the geometry type
1051  for (int j = 0; j < nv; j++)
1052  {
1053  elemdata[j] = vertex_marker[elemdata[j]];
1054  }
1055  elemdata += nv;
1056 
1057  el_marker[elems[el]] = el;
1058  }
1059 
1060  for (int i = 0; i < num_sfaces; i++)
1061  {
1062  facedata[2*i] = el_marker[facedata[2*i]];
1063  }
1064  }
1065 
1066  MPI_Waitall(num_face_nbrs, recv_requests, statuses);
1067 
1068  Array<int> recv_face_nbr_facedata;
1069  Table recv_face_nbr_elemdata;
1070 
1071  // fill-in face_nbr_elements_offset, face_nbr_vertices_offset
1072  face_nbr_elements_offset.SetSize(num_face_nbrs + 1);
1073  face_nbr_vertices_offset.SetSize(num_face_nbrs + 1);
1074  recv_face_nbr_elemdata.MakeI(num_face_nbrs);
1075  face_nbr_elements_offset[0] = 0;
1076  face_nbr_vertices_offset[0] = 0;
1077  for (int fn = 0; fn < num_face_nbrs; fn++)
1078  {
1079  face_nbr_elements_offset[fn+1] =
1080  face_nbr_elements_offset[fn] + nbr_recv_data[3*fn];
1081  face_nbr_vertices_offset[fn+1] =
1082  face_nbr_vertices_offset[fn] + nbr_recv_data[3*fn+1];
1083  recv_face_nbr_elemdata.AddColumnsInRow(fn, nbr_recv_data[3*fn+2]);
1084  }
1085  recv_face_nbr_elemdata.MakeJ();
1086 
1087  MPI_Waitall(num_face_nbrs, send_requests, statuses);
1088 
1089  // send and receive the element data
1090  for (int fn = 0; fn < num_face_nbrs; fn++)
1091  {
1092  int nbr_rank = GetFaceNbrRank(fn);
1093  int tag = 0;
1094 
1095  MPI_Isend(send_face_nbr_elemdata.GetRow(fn),
1096  send_face_nbr_elemdata.RowSize(fn),
1097  MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
1098 
1099  MPI_Irecv(recv_face_nbr_elemdata.GetRow(fn),
1100  recv_face_nbr_elemdata.RowSize(fn),
1101  MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
1102  }
1103 
1104  // convert the element data into face_nbr_elements
1105  face_nbr_elements.SetSize(face_nbr_elements_offset[num_face_nbrs]);
1106  while (true)
1107  {
1108  int fn;
1109  MPI_Waitany(num_face_nbrs, recv_requests, &fn, statuses);
1110 
1111  if (fn == MPI_UNDEFINED)
1112  {
1113  break;
1114  }
1115 
1116  int vert_off = face_nbr_vertices_offset[fn];
1117  int elem_off = face_nbr_elements_offset[fn];
1118  int num_elems = face_nbr_elements_offset[fn+1] - elem_off;
1119  int *recv_elemdata = recv_face_nbr_elemdata.GetRow(fn);
1120 
1121  for (int i = 0; i < num_elems; i++)
1122  {
1123  Element *el = NewElement(recv_elemdata[1]);
1124  el->SetAttribute(recv_elemdata[0]);
1125  recv_elemdata += 2;
1126  int nv = el->GetNVertices();
1127  for (int j = 0; j < nv; j++)
1128  {
1129  recv_elemdata[j] += vert_off;
1130  }
1131  el->SetVertices(recv_elemdata);
1132  recv_elemdata += nv;
1133  face_nbr_elements[elem_off++] = el;
1134  }
1135  }
1136 
1137  MPI_Waitall(num_face_nbrs, send_requests, statuses);
1138 
1139  // send and receive the face data
1140  recv_face_nbr_facedata.SetSize(
1141  send_face_nbr_facedata.Size_of_connections());
1142  for (int fn = 0; fn < num_face_nbrs; fn++)
1143  {
1144  int nbr_rank = GetFaceNbrRank(fn);
1145  int tag = 0;
1146 
1147  MPI_Isend(send_face_nbr_facedata.GetRow(fn),
1148  send_face_nbr_facedata.RowSize(fn),
1149  MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
1150 
1151  // the size of the send and receive face data is the same
1152  MPI_Irecv(&recv_face_nbr_facedata[send_face_nbr_facedata.GetI()[fn]],
1153  send_face_nbr_facedata.RowSize(fn),
1154  MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
1155  }
1156 
1157  // transfer the received face data into faces_info
1158  while (true)
1159  {
1160  int fn;
1161  MPI_Waitany(num_face_nbrs, recv_requests, &fn, statuses);
1162 
1163  if (fn == MPI_UNDEFINED)
1164  {
1165  break;
1166  }
1167 
1168  int elem_off = face_nbr_elements_offset[fn];
1169  int nbr_group = face_nbr_group[fn];
1170  int num_sfaces = gr_sface->RowSize(nbr_group-1);
1171  int *sface = gr_sface->GetRow(nbr_group-1);
1172  int *facedata =
1173  &recv_face_nbr_facedata[send_face_nbr_facedata.GetI()[fn]];
1174 
1175  for (int i = 0; i < num_sfaces; i++)
1176  {
1177  int lface = s2l_face[sface[i]];
1178  FaceInfo &face_info = faces_info[lface];
1179  face_info.Elem2No = -1 - (facedata[2*i] + elem_off);
1180  int info = facedata[2*i+1];
1181  // change the orientation in info to be relative to the local face
1182  if (Dim < 3)
1183  {
1184  info++; // orientation 0 --> orientation 1
1185  }
1186  else
1187  {
1188  int nbr_ori = info%64, nbr_v[4];
1189  Element *lf = faces[lface];
1190  const int *sf_v = shared_faces[sface[i]]->GetVertices();
1191 
1192  if (lf->GetGeometryType() == Geometry::TRIANGLE)
1193  {
1194  // apply the nbr_ori to sf_v to get nbr_v
1195  const int *perm = tri_orientations[nbr_ori];
1196  for (int j = 0; j < 3; j++)
1197  {
1198  nbr_v[perm[j]] = sf_v[j];
1199  }
1200  // get the orientation of nbr_v w.r.t. the local face
1201  nbr_ori = GetTriOrientation(lf->GetVertices(), nbr_v);
1202  }
1203  else
1204  {
1205  // apply the nbr_ori to sf_v to get nbr_v
1206  const int *perm = quad_orientations[nbr_ori];
1207  for (int j = 0; j < 4; j++)
1208  {
1209  nbr_v[perm[j]] = sf_v[j];
1210  }
1211  // get the orientation of nbr_v w.r.t. the local face
1212  nbr_ori = GetQuadOrientation(lf->GetVertices(), nbr_v);
1213  }
1214 
1215  info = 64*(info/64) + nbr_ori;
1216  }
1217  face_info.Elem2Inf = info;
1218  }
1219  }
1220 
1221  MPI_Waitall(num_face_nbrs, send_requests, statuses);
1222 
1223  // allocate the face_nbr_vertices
1224  face_nbr_vertices.SetSize(face_nbr_vertices_offset[num_face_nbrs]);
1225 
1226  delete [] nbr_data;
1227 
1228  delete [] statuses;
1229  delete [] requests;
1230 
1231  have_face_nbr_data = true;
1232 
1234 }
1235 
1237 {
1238  if (!have_face_nbr_data)
1239  {
1240  ExchangeFaceNbrData(); // calls this method at the end
1241  }
1242  else if (Nodes == NULL)
1243  {
1244  int num_face_nbrs = GetNFaceNeighbors();
1245 
1246  MPI_Request *requests = new MPI_Request[2*num_face_nbrs];
1247  MPI_Request *send_requests = requests;
1248  MPI_Request *recv_requests = requests + num_face_nbrs;
1249  MPI_Status *statuses = new MPI_Status[num_face_nbrs];
1250 
1251  // allocate buffer and copy the vertices to be sent
1253  for (int i = 0; i < send_vertices.Size(); i++)
1254  {
1255  send_vertices[i] = vertices[send_face_nbr_vertices.GetJ()[i]];
1256  }
1257 
1258  // send and receive the vertices
1259  for (int fn = 0; fn < num_face_nbrs; fn++)
1260  {
1261  int nbr_rank = GetFaceNbrRank(fn);
1262  int tag = 0;
1263 
1264  MPI_Isend(send_vertices[send_face_nbr_vertices.GetI()[fn]](),
1266  MPI_DOUBLE, nbr_rank, tag, MyComm, &send_requests[fn]);
1267 
1269  3*(face_nbr_vertices_offset[fn+1] -
1271  MPI_DOUBLE, nbr_rank, tag, MyComm, &recv_requests[fn]);
1272  }
1273 
1274  MPI_Waitall(num_face_nbrs, recv_requests, statuses);
1275  MPI_Waitall(num_face_nbrs, send_requests, statuses);
1276 
1277  delete [] statuses;
1278  delete [] requests;
1279  }
1280  else
1281  {
1282  ParGridFunction *pNodes = dynamic_cast<ParGridFunction *>(Nodes);
1283  if (pNodes)
1284  {
1285  pNodes->ExchangeFaceNbrData();
1286  }
1287  else
1288  mfem_error("ParMesh::ExchangeFaceNbrNodes() : "
1289  "Nodes are not ParGridFunction!");
1290  }
1291 }
1292 
1293 int ParMesh::GetFaceNbrRank(int fn) const
1294 {
1295  int nbr_group = face_nbr_group[fn];
1296  const int *nbs = gtopo.GetGroup(nbr_group);
1297  int nbr_lproc = (nbs[0]) ? nbs[0] : nbs[1];
1298  int nbr_rank = gtopo.GetNeighborRank(nbr_lproc);
1299 
1300  return nbr_rank;
1301 }
1302 
1304 {
1305  const Array<int> *s2l_face;
1306  if (Dim == 1)
1307  {
1308  s2l_face = &svert_lvert;
1309  }
1310  else if (Dim == 2)
1311  {
1312  s2l_face = &sedge_ledge;
1313  }
1314  else
1315  {
1316  s2l_face = &sface_lface;
1317  }
1318 
1319  Table *face_elem = new Table;
1320 
1321  face_elem->MakeI(faces_info.Size());
1322 
1323  for (int i = 0; i < faces_info.Size(); i++)
1324  {
1325  if (faces_info[i].Elem2No >= 0)
1326  {
1327  face_elem->AddColumnsInRow(i, 2);
1328  }
1329  else
1330  {
1331  face_elem->AddAColumnInRow(i);
1332  }
1333  }
1334  for (int i = 0; i < s2l_face->Size(); i++)
1335  {
1336  face_elem->AddAColumnInRow((*s2l_face)[i]);
1337  }
1338 
1339  face_elem->MakeJ();
1340 
1341  for (int i = 0; i < faces_info.Size(); i++)
1342  {
1343  face_elem->AddConnection(i, faces_info[i].Elem1No);
1344  if (faces_info[i].Elem2No >= 0)
1345  {
1346  face_elem->AddConnection(i, faces_info[i].Elem2No);
1347  }
1348  }
1349  for (int i = 0; i < s2l_face->Size(); i++)
1350  {
1351  int lface = (*s2l_face)[i];
1352  int nbr_elem_idx = -1 - faces_info[lface].Elem2No;
1353  face_elem->AddConnection(lface, NumOfElements + nbr_elem_idx);
1354  }
1355 
1356  face_elem->ShiftUpI();
1357 
1358  return face_elem;
1359 }
1360 
1362 {
1363  int FaceNo = GetSharedFace(sf);
1364 
1365  // fill-in the face and the first (local) element data into FaceElemTr
1367 
1368  FaceInfo &face_info = faces_info[FaceNo];
1369 
1370  // setup the transformation for the second (neighbor) element
1371  FaceElemTr.Elem2No = -1 - face_info.Elem2No;
1372  GetFaceNbrElementTransformation(FaceElemTr.Elem2No, &Transformation2);
1374 
1375  // setup Loc2
1376  int face_type = (Dim == 1) ? Element::POINT : faces[FaceNo]->GetType();
1377  switch (face_type)
1378  {
1379  case Element::POINT:
1381  face_info.Elem2Inf);
1382  break;
1383 
1384  case Element::SEGMENT:
1387  face_info.Elem2Inf);
1388  else // assume the element is a quad
1390  face_info.Elem2Inf);
1391  break;
1392 
1393  case Element::TRIANGLE:
1394  // --------- assumes the face is a triangle -- face of a tetrahedron
1396  face_info.Elem2Inf);
1397  break;
1398 
1400  // --------- assumes the face is a quad -- face of a hexahedron
1402  face_info.Elem2Inf);
1403  break;
1404  }
1405 
1406  return &FaceElemTr;
1407 }
1408 
1410 {
1411  if (Dim == 1)
1412  {
1413  return svert_lvert.Size();
1414  }
1415  if (Dim == 2)
1416  {
1417  return sedge_ledge.Size();
1418  }
1419  return sface_lface.Size();
1420 }
1421 
1422 int ParMesh::GetSharedFace(int sface) const
1423 {
1424  switch (Dim)
1425  {
1426  case 1: return svert_lvert[sface];
1427  case 2: return sedge_ledge[sface];
1428  }
1429  return sface_lface[sface];
1430 }
1431 
1433 {
1434  if (Dim != 3 || !(meshgen & 1))
1435  {
1436  return;
1437  }
1438 
1440 
1441  int *v;
1442 
1443  // The local edge and face numbering is changed therefore we need to
1444  // update sedge_ledge and sface_lface.
1445  {
1446  DSTable v_to_v(NumOfVertices);
1447  GetVertexToVertexTable(v_to_v);
1448  for (int i = 0; i < shared_edges.Size(); i++)
1449  {
1450  v = shared_edges[i]->GetVertices();
1451  sedge_ledge[i] = v_to_v(v[0], v[1]);
1452  }
1453  }
1454 
1455  // Rotate shared faces and update sface_lface.
1456  // Note that no communication is needed to ensure that the shared
1457  // faces are rotated in the same way in both processors. This is
1458  // automatic due to various things, e.g. the global to local vertex
1459  // mapping preserves the global order; also the way new vertices
1460  // are introduced during refinement is essential.
1461  {
1462  STable3D *faces_tbl = GetFacesTable();
1463  for (int i = 0; i < shared_faces.Size(); i++)
1464  if (shared_faces[i]->GetType() == Element::TRIANGLE)
1465  {
1466  v = shared_faces[i]->GetVertices();
1467 
1468  Rotate3(v[0], v[1], v[2]);
1469 
1470  sface_lface[i] = (*faces_tbl)(v[0], v[1], v[2]);
1471  }
1472  delete faces_tbl;
1473  }
1474 }
1475 
1476 void ParMesh::LocalRefinement(const Array<int> &marked_el, int type)
1477 {
1478  int i, j, wtls = WantTwoLevelState;
1479 
1480  if (Nodes) // curved mesh
1481  {
1482  UseTwoLevelState(1);
1483  }
1484 
1487  DeleteFaceNbrData();
1488 
1489  if (Dim == 3)
1490  {
1491  if (WantTwoLevelState)
1492  {
1498  }
1499 
1500  int uniform_refinement = 0;
1501  if (type < 0)
1502  {
1503  type = -type;
1504  uniform_refinement = 1;
1505  }
1506 
1507  // 1. Get table of vertex to vertex connections.
1508  DSTable v_to_v(NumOfVertices);
1509  GetVertexToVertexTable(v_to_v);
1510 
1511  // 2. Get edge to element connections in arrays edge1 and edge2
1512  Array<int> middle(v_to_v.NumberOfEntries());
1513  middle = -1;
1514 
1515  // 3. Do the red refinement.
1516  switch (type)
1517  {
1518  case 1:
1519  for (i = 0; i < marked_el.Size(); i++)
1520  {
1521  Bisection(marked_el[i], v_to_v, NULL, NULL, middle);
1522  }
1523  break;
1524  case 2:
1525  for (i = 0; i < marked_el.Size(); i++)
1526  {
1527  Bisection(marked_el[i], v_to_v, NULL, NULL, middle);
1528 
1529  Bisection(NumOfElements - 1, v_to_v, NULL, NULL, middle);
1530  Bisection(marked_el[i], v_to_v, NULL, NULL, middle);
1531  }
1532  break;
1533  case 3:
1534  for (i = 0; i < marked_el.Size(); i++)
1535  {
1536  Bisection(marked_el[i], v_to_v, NULL, NULL, middle);
1537 
1538  j = NumOfElements - 1;
1539  Bisection(j, v_to_v, NULL, NULL, middle);
1540  Bisection(NumOfElements - 1, v_to_v, NULL, NULL, middle);
1541  Bisection(j, v_to_v, NULL, NULL, middle);
1542 
1543  Bisection(marked_el[i], v_to_v, NULL, NULL, middle);
1544  Bisection(NumOfElements-1, v_to_v, NULL, NULL, middle);
1545  Bisection(marked_el[i], v_to_v, NULL, NULL, middle);
1546  }
1547  break;
1548  }
1549 
1550  if (WantTwoLevelState)
1551  {
1554  }
1555 
1556  // 4. Do the green refinement (to get conforming mesh).
1557  int need_refinement;
1558  int refined_edge[5][3] =
1559  {
1560  {0, 0, 0},
1561  {1, 0, 0},
1562  {1, 1, 0},
1563  {1, 0, 1},
1564  {1, 1, 1}
1565  };
1566  int faces_in_group, max_faces_in_group = 0;
1567  // face_splittings identify how the shared faces have been split
1568  int **face_splittings = new int*[GetNGroups()-1];
1569  for (i = 0; i < GetNGroups()-1; i++)
1570  {
1571  faces_in_group = GroupNFaces(i+1);
1572  face_splittings[i] = new int[faces_in_group];
1573  if (faces_in_group > max_faces_in_group)
1574  {
1575  max_faces_in_group = faces_in_group;
1576  }
1577  }
1578  int neighbor, *iBuf = new int[max_faces_in_group];
1579 
1580  Array<int> group_faces;
1581  Vertex V;
1582 
1583  MPI_Request request;
1584  MPI_Status status;
1585 
1586 #ifdef MFEM_DEBUG
1587  int ref_loops_all = 0, ref_loops_par = 0;
1588 #endif
1589  do
1590  {
1591  need_refinement = 0;
1592  for (i = 0; i < NumOfElements; i++)
1593  {
1594  if (elements[i]->NeedRefinement(v_to_v, middle))
1595  {
1596  need_refinement = 1;
1597  Bisection(i, v_to_v, NULL, NULL, middle);
1598  }
1599  }
1600 #ifdef MFEM_DEBUG
1601  ref_loops_all++;
1602 #endif
1603 
1604  if (uniform_refinement)
1605  {
1606  continue;
1607  }
1608 
1609  // if the mesh is locally conforming start making it globally
1610  // conforming
1611  if (need_refinement == 0)
1612  {
1613 #ifdef MFEM_DEBUG
1614  ref_loops_par++;
1615 #endif
1616  // MPI_Barrier(MyComm);
1617 
1618  // (a) send the type of interface splitting
1619  for (i = 0; i < GetNGroups()-1; i++)
1620  {
1621  group_sface.GetRow(i, group_faces);
1622  faces_in_group = group_faces.Size();
1623  // it is enough to communicate through the faces
1624  if (faces_in_group != 0)
1625  {
1626  for (j = 0; j < faces_in_group; j++)
1627  face_splittings[i][j] =
1628  GetFaceSplittings(shared_faces[group_faces[j]], v_to_v,
1629  middle);
1630  const int *nbs = gtopo.GetGroup(i+1);
1631  if (nbs[0] == 0)
1632  {
1633  neighbor = gtopo.GetNeighborRank(nbs[1]);
1634  }
1635  else
1636  {
1637  neighbor = gtopo.GetNeighborRank(nbs[0]);
1638  }
1639  MPI_Isend(face_splittings[i], faces_in_group, MPI_INT,
1640  neighbor, 0, MyComm, &request);
1641  }
1642  }
1643 
1644  // (b) receive the type of interface splitting
1645  for (i = 0; i < GetNGroups()-1; i++)
1646  {
1647  group_sface.GetRow(i, group_faces);
1648  faces_in_group = group_faces.Size();
1649  if (faces_in_group != 0)
1650  {
1651  const int *nbs = gtopo.GetGroup(i+1);
1652  if (nbs[0] == 0)
1653  {
1654  neighbor = gtopo.GetNeighborRank(nbs[1]);
1655  }
1656  else
1657  {
1658  neighbor = gtopo.GetNeighborRank(nbs[0]);
1659  }
1660  MPI_Recv(iBuf, faces_in_group, MPI_INT, neighbor,
1661  MPI_ANY_TAG, MyComm, &status);
1662 
1663  for (j = 0; j < faces_in_group; j++)
1664  if (iBuf[j] != face_splittings[i][j])
1665  {
1666  int *v = shared_faces[group_faces[j]]->GetVertices();
1667  for (int k = 0; k < 3; k++)
1668  if (refined_edge[iBuf[j]][k] == 1 &&
1669  refined_edge[face_splittings[i][j]][k] == 0)
1670  {
1671  int ii = v_to_v(v[k], v[(k+1)%3]);
1672  if (middle[ii] == -1)
1673  {
1674  need_refinement = 1;
1675  middle[ii] = NumOfVertices++;
1676  for (int c = 0; c < 3; c++)
1677  V(c) = 0.5 * (vertices[v[k]](c) +
1678  vertices[v[(k+1)%3]](c));
1679  vertices.Append(V);
1680  }
1681  }
1682  }
1683  }
1684  }
1685 
1686  i = need_refinement;
1687  MPI_Allreduce(&i, &need_refinement, 1, MPI_INT, MPI_LOR, MyComm);
1688  }
1689  }
1690  while (need_refinement == 1);
1691 
1692 #ifdef MFEM_DEBUG
1693  i = ref_loops_all;
1694  MPI_Reduce(&i, &ref_loops_all, 1, MPI_INT, MPI_MAX, 0, MyComm);
1695  if (MyRank == 0)
1696  {
1697  cout << "\n\nParMesh::LocalRefinement : max. ref_loops_all = "
1698  << ref_loops_all << ", ref_loops_par = " << ref_loops_par
1699  << '\n' << endl;
1700  }
1701 #endif
1702 
1703  delete [] iBuf;
1704  for (i = 0; i < GetNGroups()-1; i++)
1705  {
1706  delete [] face_splittings[i];
1707  }
1708  delete [] face_splittings;
1709 
1710 
1711  // 5. Update the boundary elements.
1712  do
1713  {
1714  need_refinement = 0;
1715  for (i = 0; i < NumOfBdrElements; i++)
1716  if (boundary[i]->NeedRefinement(v_to_v, middle))
1717  {
1718  need_refinement = 1;
1719  Bisection(i, v_to_v, middle);
1720  }
1721  }
1722  while (need_refinement == 1);
1723 
1724  if (NumOfBdrElements != boundary.Size())
1725  mfem_error("ParMesh::LocalRefinement :"
1726  " (NumOfBdrElements != boundary.Size())");
1727 
1728  // 5a. Update the groups after refinement.
1729  if (el_to_face != NULL)
1730  {
1731  if (WantTwoLevelState)
1732  {
1734  el_to_face = NULL;
1736  }
1737  RefineGroups(v_to_v, middle);
1738  // GetElementToFaceTable(); // Called by RefineGroups
1739  GenerateFaces();
1740  if (WantTwoLevelState)
1741  {
1743  }
1744  }
1745 
1746  // 6. Un-mark the Pf elements.
1747  int refinement_edges[2], type, flag;
1748  for (i = 0; i < NumOfElements; i++)
1749  {
1750  Element *El = elements[i];
1751  while (El->GetType() == Element::BISECTED)
1752  {
1753  El = ((BisectedElement *) El)->FirstChild;
1754  }
1755  ((Tetrahedron *) El)->ParseRefinementFlag(refinement_edges,
1756  type, flag);
1757  if (type == Tetrahedron::TYPE_PF)
1758  ((Tetrahedron *) El)->CreateRefinementFlag(refinement_edges,
1760  flag);
1761  }
1762 
1763  // 7. Free the allocated memory.
1764  middle.DeleteAll();
1765 
1766  if (el_to_edge != NULL)
1767  {
1768  if (WantTwoLevelState)
1769  {
1771  f_el_to_edge = new Table;
1773  bel_to_edge = NULL;
1777  }
1778  else
1779  {
1781  }
1782  }
1783 
1784  if (WantTwoLevelState)
1785  {
1791  }
1792  } // 'if (Dim == 3)'
1793 
1794 
1795  if (Dim == 2)
1796  {
1797  if (WantTwoLevelState)
1798  {
1803  }
1804 
1805  int uniform_refinement = 0;
1806  if (type < 0)
1807  {
1808  type = -type;
1809  uniform_refinement = 1;
1810  }
1811 
1812  // 1. Get table of vertex to vertex connections.
1813  DSTable v_to_v(NumOfVertices);
1814  GetVertexToVertexTable(v_to_v);
1815 
1816  // 2. Get edge to element connections in arrays edge1 and edge2
1817  int nedges = v_to_v.NumberOfEntries();
1818  int *edge1 = new int[nedges];
1819  int *edge2 = new int[nedges];
1820  int *middle = new int[nedges];
1821 
1822  for (i = 0; i < nedges; i++)
1823  {
1824  edge1[i] = edge2[i] = middle[i] = -1;
1825  }
1826 
1827  for (i = 0; i < NumOfElements; i++)
1828  {
1829  int *v = elements[i]->GetVertices();
1830  for (j = 0; j < 3; j++)
1831  {
1832  int ind = v_to_v(v[j], v[(j+1)%3]);
1833  (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
1834  }
1835  }
1836 
1837  // 3. Do the red refinement.
1838  for (i = 0; i < marked_el.Size(); i++)
1839  {
1840  RedRefinement(marked_el[i], v_to_v, edge1, edge2, middle);
1841  }
1842 
1843  if (WantTwoLevelState)
1844  {
1847  }
1848 
1849  // 4. Do the green refinement (to get conforming mesh).
1850  int need_refinement;
1851  int edges_in_group, max_edges_in_group = 0;
1852  // edge_splittings identify how the shared edges have been split
1853  int **edge_splittings = new int*[GetNGroups()-1];
1854  for (i = 0; i < GetNGroups()-1; i++)
1855  {
1856  edges_in_group = GroupNEdges(i+1);
1857  edge_splittings[i] = new int[edges_in_group];
1858  if (edges_in_group > max_edges_in_group)
1859  {
1860  max_edges_in_group = edges_in_group;
1861  }
1862  }
1863  int neighbor, *iBuf = new int[max_edges_in_group];
1864 
1865  Array<int> group_edges;
1866 
1867  MPI_Request request;
1868  MPI_Status status;
1869  Vertex V;
1870  V(2) = 0.0;
1871 
1872 #ifdef MFEM_DEBUG
1873  int ref_loops_all = 0, ref_loops_par = 0;
1874 #endif
1875  do
1876  {
1877  need_refinement = 0;
1878  for (i = 0; i < nedges; i++)
1879  if (middle[i] != -1 && edge1[i] != -1)
1880  {
1881  need_refinement = 1;
1882  GreenRefinement(edge1[i], v_to_v, edge1, edge2, middle);
1883  }
1884 #ifdef MFEM_DEBUG
1885  ref_loops_all++;
1886 #endif
1887 
1888  if (uniform_refinement)
1889  {
1890  continue;
1891  }
1892 
1893  // if the mesh is locally conforming start making it globally
1894  // conforming
1895  if (need_refinement == 0)
1896  {
1897 #ifdef MFEM_DEBUG
1898  ref_loops_par++;
1899 #endif
1900  // MPI_Barrier(MyComm);
1901 
1902  // (a) send the type of interface splitting
1903  for (i = 0; i < GetNGroups()-1; i++)
1904  {
1905  group_sedge.GetRow(i, group_edges);
1906  edges_in_group = group_edges.Size();
1907  // it is enough to communicate through the edges
1908  if (edges_in_group != 0)
1909  {
1910  for (j = 0; j < edges_in_group; j++)
1911  edge_splittings[i][j] =
1912  GetEdgeSplittings(shared_edges[group_edges[j]], v_to_v,
1913  middle);
1914  const int *nbs = gtopo.GetGroup(i+1);
1915  if (nbs[0] == 0)
1916  {
1917  neighbor = gtopo.GetNeighborRank(nbs[1]);
1918  }
1919  else
1920  {
1921  neighbor = gtopo.GetNeighborRank(nbs[0]);
1922  }
1923  MPI_Isend(edge_splittings[i], edges_in_group, MPI_INT,
1924  neighbor, 0, MyComm, &request);
1925  }
1926  }
1927 
1928  // (b) receive the type of interface splitting
1929  for (i = 0; i < GetNGroups()-1; i++)
1930  {
1931  group_sedge.GetRow(i, group_edges);
1932  edges_in_group = group_edges.Size();
1933  if (edges_in_group != 0)
1934  {
1935  const int *nbs = gtopo.GetGroup(i+1);
1936  if (nbs[0] == 0)
1937  {
1938  neighbor = gtopo.GetNeighborRank(nbs[1]);
1939  }
1940  else
1941  {
1942  neighbor = gtopo.GetNeighborRank(nbs[0]);
1943  }
1944  MPI_Recv(iBuf, edges_in_group, MPI_INT, neighbor,
1945  MPI_ANY_TAG, MyComm, &status);
1946 
1947  for (j = 0; j < edges_in_group; j++)
1948  if (iBuf[j] == 1 && edge_splittings[i][j] == 0)
1949  {
1950  int *v = shared_edges[group_edges[j]]->GetVertices();
1951  int ii = v_to_v(v[0], v[1]);
1952 #ifdef MFEM_DEBUG
1953  if (middle[ii] != -1)
1954  mfem_error("ParMesh::LocalRefinement (triangles) : "
1955  "Oops!");
1956 #endif
1957  need_refinement = 1;
1958  middle[ii] = NumOfVertices++;
1959  for (int c = 0; c < 2; c++)
1960  {
1961  V(c) = 0.5 * (vertices[v[0]](c) + vertices[v[1]](c));
1962  }
1963  vertices.Append(V);
1964  }
1965  }
1966  }
1967 
1968  i = need_refinement;
1969  MPI_Allreduce(&i, &need_refinement, 1, MPI_INT, MPI_LOR, MyComm);
1970  }
1971  }
1972  while (need_refinement == 1);
1973 
1974 #ifdef MFEM_DEBUG
1975  i = ref_loops_all;
1976  MPI_Reduce(&i, &ref_loops_all, 1, MPI_INT, MPI_MAX, 0, MyComm);
1977  if (MyRank == 0)
1978  {
1979  cout << "\n\nParMesh::LocalRefinement : max. ref_loops_all = "
1980  << ref_loops_all << ", ref_loops_par = " << ref_loops_par
1981  << '\n' << endl;
1982  }
1983 #endif
1984 
1985  for (i = 0; i < GetNGroups()-1; i++)
1986  {
1987  delete [] edge_splittings[i];
1988  }
1989  delete [] edge_splittings;
1990 
1991  delete [] iBuf;
1992 
1993  // 5. Update the boundary elements.
1994  int v1[2], v2[2], bisect, temp;
1995  temp = NumOfBdrElements;
1996  for (i = 0; i < temp; i++)
1997  {
1998  int *v = boundary[i]->GetVertices();
1999  bisect = v_to_v(v[0], v[1]);
2000  if (middle[bisect] != -1)
2001  {
2002  // the element was refined (needs updating)
2003  if (boundary[i]->GetType() == Element::SEGMENT)
2004  {
2005  v1[0] = v[0]; v1[1] = middle[bisect];
2006  v2[0] = middle[bisect]; v2[1] = v[1];
2007 
2008  if (WantTwoLevelState)
2009  {
2010  boundary.Append(new Segment(v2, boundary[i]->GetAttribute()));
2011 #ifdef MFEM_USE_MEMALLOC
2012  BisectedElement *aux = BEMemory.Alloc();
2013  aux->SetCoarseElem(boundary[i]);
2014 #else
2015  BisectedElement *aux = new BisectedElement(boundary[i]);
2016 #endif
2017  aux->FirstChild =
2018  new Segment(v1, boundary[i]->GetAttribute());
2019  aux->SecondChild = NumOfBdrElements;
2020  boundary[i] = aux;
2021  NumOfBdrElements++;
2022  }
2023  else
2024  {
2025  boundary[i]->SetVertices(v1);
2026  boundary.Append(new Segment(v2, boundary[i]->GetAttribute()));
2027  }
2028  }
2029  else
2030  mfem_error("Only bisection of segment is implemented for bdr"
2031  " elem.");
2032  }
2033  }
2034  NumOfBdrElements = boundary.Size();
2035 
2036  // 5a. Update the groups after refinement.
2037  RefineGroups(v_to_v, middle);
2038 
2039  // 6. Free the allocated memory.
2040  delete [] edge1;
2041  delete [] edge2;
2042  delete [] middle;
2043 
2044  if (WantTwoLevelState)
2045  {
2051  }
2052 
2053  if (el_to_edge != NULL)
2054  {
2055  if (WantTwoLevelState)
2056  {
2058  mfem::Swap(be_to_edge, fc_be_to_edge); // save coarse be_to_edge
2059  f_el_to_edge = new Table;
2063  }
2064  else
2065  {
2067  }
2068  GenerateFaces();
2069  }
2070  } // 'if (Dim == 2)'
2071 
2072  if (Dim == 1) // --------------------------------------------------------
2073  {
2074  if (WantTwoLevelState)
2075  {
2079  c_NumOfEdges = 0;
2080  }
2081  int cne = NumOfElements, cnv = NumOfVertices;
2082  NumOfVertices += marked_el.Size();
2083  NumOfElements += marked_el.Size();
2084  vertices.SetSize(NumOfVertices);
2085  elements.SetSize(NumOfElements);
2086  for (j = 0; j < marked_el.Size(); j++)
2087  {
2088  i = marked_el[j];
2089  Segment *c_seg = (Segment *)elements[i];
2090  int *vert = c_seg->GetVertices(), attr = c_seg->GetAttribute();
2091  int new_v = cnv + j, new_e = cne + j;
2092  AverageVertices(vert, 2, new_v);
2093  elements[new_e] = new Segment(new_v, vert[1], attr);
2094  if (WantTwoLevelState)
2095  {
2096 #ifdef MFEM_USE_MEMALLOC
2097  BisectedElement *aux = BEMemory.Alloc();
2098  aux->SetCoarseElem(c_seg);
2099 #else
2100  BisectedElement *aux = new BisectedElement(c_seg);
2101 #endif
2102  aux->FirstChild = new Segment(vert[0], new_v, attr);
2103  aux->SecondChild = new_e;
2104  elements[i] = aux;
2105  }
2106  else
2107  {
2108  vert[1] = new_v;
2109  }
2110  }
2111  if (WantTwoLevelState)
2112  {
2116  f_NumOfEdges = 0;
2117 
2120  }
2121  GenerateFaces();
2122  } // end of 'if (Dim == 1)'
2123 
2124  if (Nodes) // curved mesh
2125  {
2126  UpdateNodes();
2127  UseTwoLevelState(wtls);
2128  }
2129 
2130 #ifdef MFEM_DEBUG
2131  CheckElementOrientation(false);
2133 #endif
2134 }
2135 
2136 void ParMesh::NonconformingRefinement(const Array<Refinement> &refinements,
2137  int nc_limit)
2138 {
2139  if (NURBSext)
2140  {
2141  MFEM_ABORT("ParMesh::NonconformingRefinement: NURBS meshes are not "
2142  "supported. Project the NURBS to Nodes first.");
2143  }
2144 
2145  int wtls = WantTwoLevelState;
2146 
2147  if (Nodes) // curved mesh
2148  {
2149  UseTwoLevelState(1);
2150  }
2151 
2154 
2155  if (!pncmesh)
2156  {
2157  MFEM_ABORT("Can't convert conforming ParMesh to nonconforming ParMesh "
2158  "(you need to initialize the ParMesh from a nonconforming "
2159  "serial Mesh)");
2160  }
2161 
2162  if (WantTwoLevelState)
2163  {
2165  }
2166 
2167  // do the refinements
2168  pncmesh->Refine(refinements);
2169 
2170  if (nc_limit > 0)
2171  {
2172  pncmesh->LimitNCLevel(nc_limit);
2173  }
2174 
2175  // create a second mesh containing the finest elements from 'pncmesh'
2176  ParMesh* pmesh2 = new ParMesh(*pncmesh);
2177  pncmesh->OnMeshUpdated(pmesh2);
2178 
2179  attributes.Copy(pmesh2->attributes);
2180  bdr_attributes.Copy(pmesh2->bdr_attributes);
2181 
2182  // now swap the meshes, the second mesh will become the old coarse mesh
2183  // and this mesh will be the new fine mesh
2184  Swap(*pmesh2, false);
2185 
2186  // retain the coarse mesh if two-level state was requested, delete otherwise
2187  if (WantTwoLevelState)
2188  {
2189  nc_coarse_level = pmesh2;
2191  }
2192  else
2193  {
2194  delete pmesh2;
2195  }
2196 
2197  if (Nodes) // curved mesh
2198  {
2199  UpdateNodes();
2200  UseTwoLevelState(wtls);
2201  }
2202 }
2203 
2204 void ParMesh::RefineGroups(const DSTable &v_to_v, int *middle)
2205 {
2206  int i, attr, newv[3], ind, f_ind, *v;
2207 
2208  int group;
2209  Array<int> group_verts, group_edges, group_faces;
2210 
2211  // To update the groups after a refinement, we observe that:
2212  // - every (new and old) vertex, edge and face belongs to exactly one group
2213  // - the refinement does not create new groups
2214  // - a new vertex appears only as the middle of a refined edge
2215  // - a face can be refined 2, 3 or 4 times producing new edges and faces
2216 
2217  int *I_group_svert, *J_group_svert;
2218  int *I_group_sedge, *J_group_sedge;
2219  int *I_group_sface, *J_group_sface;
2220 
2221  I_group_svert = new int[GetNGroups()+1];
2222  I_group_sedge = new int[GetNGroups()+1];
2223  if (Dim == 3)
2224  {
2225  I_group_sface = new int[GetNGroups()+1];
2226  }
2227  else
2228  {
2229  I_group_sface = NULL;
2230  }
2231 
2232  I_group_svert[0] = I_group_svert[1] = 0;
2233  I_group_sedge[0] = I_group_sedge[1] = 0;
2234  if (Dim == 3)
2235  {
2236  I_group_sface[0] = I_group_sface[1] = 0;
2237  }
2238 
2239  // overestimate the size of the J arrays
2240  if (Dim == 3)
2241  {
2242  J_group_svert = new int[group_svert.Size_of_connections()
2243  + group_sedge.Size_of_connections()];
2244  J_group_sedge = new int[2*group_sedge.Size_of_connections()
2245  + 3*group_sface.Size_of_connections()];
2246  J_group_sface = new int[4*group_sface.Size_of_connections()];
2247  }
2248  else if (Dim == 2)
2249  {
2250  J_group_svert = new int[group_svert.Size_of_connections()
2251  + group_sedge.Size_of_connections()];
2252  J_group_sedge = new int[2*group_sedge.Size_of_connections()];
2253  J_group_sface = NULL;
2254  }
2255  else
2256  {
2257  J_group_svert = J_group_sedge = J_group_sface = NULL;
2258  }
2259 
2260  for (group = 0; group < GetNGroups()-1; group++)
2261  {
2262  // Get the group shared objects
2263  group_svert.GetRow(group, group_verts);
2264  group_sedge.GetRow(group, group_edges);
2265  group_sface.GetRow(group, group_faces);
2266 
2267  // Check which edges have been refined
2268  for (i = 0; i < group_sedge.RowSize(group); i++)
2269  {
2270  v = shared_edges[group_edges[i]]->GetVertices();
2271  ind = middle[v_to_v(v[0], v[1])];
2272  if (ind != -1)
2273  {
2274  // add a vertex
2275  group_verts.Append(svert_lvert.Append(ind)-1);
2276  // update the edges
2277  attr = shared_edges[group_edges[i]]->GetAttribute();
2278  shared_edges.Append(new Segment(v[1], ind, attr));
2279  group_edges.Append(sedge_ledge.Append(-1)-1);
2280  v[1] = ind;
2281  }
2282  }
2283 
2284  // Check which faces have been refined
2285  for (i = 0; i < group_sface.RowSize(group); i++)
2286  {
2287  v = shared_faces[group_faces[i]]->GetVertices();
2288  ind = middle[v_to_v(v[0], v[1])];
2289  if (ind != -1)
2290  {
2291  attr = shared_faces[group_faces[i]]->GetAttribute();
2292  // add the refinement edge
2293  shared_edges.Append(new Segment(v[2], ind, attr));
2294  group_edges.Append(sedge_ledge.Append(-1)-1);
2295  // add a face
2296  f_ind = group_faces.Size();
2297  shared_faces.Append(new Triangle(v[1], v[2], ind, attr));
2298  group_faces.Append(sface_lface.Append(-1)-1);
2299  newv[0] = v[2]; newv[1] = v[0]; newv[2] = ind;
2300  shared_faces[group_faces[i]]->SetVertices(newv);
2301 
2302  // check if the left face has also been refined
2303  // v = shared_faces[group_faces[i]]->GetVertices();
2304  ind = middle[v_to_v(v[0], v[1])];
2305  if (ind != -1)
2306  {
2307  // add the refinement edge
2308  shared_edges.Append(new Segment(v[2], ind, attr));
2309  group_edges.Append(sedge_ledge.Append(-1)-1);
2310  // add a face
2311  shared_faces.Append(new Triangle(v[1], v[2], ind, attr));
2312  group_faces.Append(sface_lface.Append(-1)-1);
2313  newv[0] = v[2]; newv[1] = v[0]; newv[2] = ind;
2314  shared_faces[group_faces[i]]->SetVertices(newv);
2315  }
2316 
2317  // check if the right face has also been refined
2318  v = shared_faces[group_faces[f_ind]]->GetVertices();
2319  ind = middle[v_to_v(v[0], v[1])];
2320  if (ind != -1)
2321  {
2322  // add the refinement edge
2323  shared_edges.Append(new Segment(v[2], ind, attr));
2324  group_edges.Append(sedge_ledge.Append(-1)-1);
2325  // add a face
2326  shared_faces.Append(new Triangle(v[1], v[2], ind, attr));
2327  group_faces.Append(sface_lface.Append(-1)-1);
2328  newv[0] = v[2]; newv[1] = v[0]; newv[2] = ind;
2329  shared_faces[group_faces[f_ind]]->SetVertices(newv);
2330  }
2331  }
2332  }
2333 
2334  I_group_svert[group+1] = I_group_svert[group] + group_verts.Size();
2335  I_group_sedge[group+1] = I_group_sedge[group] + group_edges.Size();
2336  if (Dim == 3)
2337  {
2338  I_group_sface[group+1] = I_group_sface[group] + group_faces.Size();
2339  }
2340 
2341  int *J;
2342  J = J_group_svert+I_group_svert[group];
2343  for (i = 0; i < group_verts.Size(); i++)
2344  {
2345  J[i] = group_verts[i];
2346  }
2347  J = J_group_sedge+I_group_sedge[group];
2348  for (i = 0; i < group_edges.Size(); i++)
2349  {
2350  J[i] = group_edges[i];
2351  }
2352  if (Dim == 3)
2353  {
2354  J = J_group_sface+I_group_sface[group];
2355  for (i = 0; i < group_faces.Size(); i++)
2356  {
2357  J[i] = group_faces[i];
2358  }
2359  }
2360  }
2361 
2362  // Fix the local numbers of shared edges and faces
2363  {
2364  DSTable new_v_to_v(NumOfVertices);
2365  GetVertexToVertexTable(new_v_to_v);
2366  for (i = 0; i < shared_edges.Size(); i++)
2367  {
2368  v = shared_edges[i]->GetVertices();
2369  sedge_ledge[i] = new_v_to_v(v[0], v[1]);
2370  }
2371  }
2372  if (Dim == 3)
2373  {
2374  STable3D *faces_tbl = GetElementToFaceTable(1);
2375  for (i = 0; i < shared_faces.Size(); i++)
2376  {
2377  v = shared_faces[i]->GetVertices();
2378  sface_lface[i] = (*faces_tbl)(v[0], v[1], v[2]);
2379  }
2380  delete faces_tbl;
2381  }
2382 
2383  group_svert.SetIJ(I_group_svert, J_group_svert);
2384  group_sedge.SetIJ(I_group_sedge, J_group_sedge);
2385  if (Dim == 3)
2386  {
2387  group_sface.SetIJ(I_group_sface, J_group_sface);
2388  }
2389 }
2390 
2391 void ParMesh::QuadUniformRefinement()
2392 {
2394  DeleteFaceNbrData();
2395 
2396  int oedge = NumOfVertices, wtls = WantTwoLevelState;
2397 
2398  if (Nodes) // curved mesh
2399  {
2400  UseTwoLevelState(1);
2401  }
2402 
2403  // call Mesh::QuadUniformRefinement so that it won't update the nodes
2404  {
2405  GridFunction *nodes = Nodes;
2406  Nodes = NULL;
2408  Nodes = nodes;
2409  }
2410 
2411  // update the groups
2412  {
2413  int i, attr, ind, *v;
2414 
2415  int group;
2416  Array<int> sverts, sedges;
2417 
2418  int *I_group_svert, *J_group_svert;
2419  int *I_group_sedge, *J_group_sedge;
2420 
2421  I_group_svert = new int[GetNGroups()+1];
2422  I_group_sedge = new int[GetNGroups()+1];
2423 
2424  I_group_svert[0] = I_group_svert[1] = 0;
2425  I_group_sedge[0] = I_group_sedge[1] = 0;
2426 
2427  // compute the size of the J arrays
2428  J_group_svert = new int[group_svert.Size_of_connections()
2429  + group_sedge.Size_of_connections()];
2430  J_group_sedge = new int[2*group_sedge.Size_of_connections()];
2431 
2432  for (group = 0; group < GetNGroups()-1; group++)
2433  {
2434  // Get the group shared objects
2435  group_svert.GetRow(group, sverts);
2436  group_sedge.GetRow(group, sedges);
2437 
2438  // Process all the edges
2439  for (i = 0; i < group_sedge.RowSize(group); i++)
2440  {
2441  v = shared_edges[sedges[i]]->GetVertices();
2442  ind = oedge + sedge_ledge[sedges[i]];
2443  // add a vertex
2444  sverts.Append(svert_lvert.Append(ind)-1);
2445  // update the edges
2446  attr = shared_edges[sedges[i]]->GetAttribute();
2447  shared_edges.Append(new Segment(v[1], ind, attr));
2448  sedges.Append(sedge_ledge.Append(-1)-1);
2449  v[1] = ind;
2450  }
2451 
2452  I_group_svert[group+1] = I_group_svert[group] + sverts.Size();
2453  I_group_sedge[group+1] = I_group_sedge[group] + sedges.Size();
2454 
2455  int *J;
2456  J = J_group_svert+I_group_svert[group];
2457  for (i = 0; i < sverts.Size(); i++)
2458  {
2459  J[i] = sverts[i];
2460  }
2461  J = J_group_sedge+I_group_sedge[group];
2462  for (i = 0; i < sedges.Size(); i++)
2463  {
2464  J[i] = sedges[i];
2465  }
2466  }
2467 
2468  // Fix the local numbers of shared edges
2469  DSTable v_to_v(NumOfVertices);
2470  GetVertexToVertexTable(v_to_v);
2471  for (i = 0; i < shared_edges.Size(); i++)
2472  {
2473  v = shared_edges[i]->GetVertices();
2474  sedge_ledge[i] = v_to_v(v[0], v[1]);
2475  }
2476 
2477  group_svert.SetIJ(I_group_svert, J_group_svert);
2478  group_sedge.SetIJ(I_group_sedge, J_group_sedge);
2479  }
2480 
2481  if (Nodes) // curved mesh
2482  {
2483  UpdateNodes();
2484  UseTwoLevelState(wtls);
2485  }
2486 }
2487 
2488 void ParMesh::HexUniformRefinement()
2489 {
2491  DeleteFaceNbrData();
2492 
2493  int wtls = WantTwoLevelState;
2494  int oedge = NumOfVertices;
2495  int oface = oedge + NumOfEdges;
2496 
2497  DSTable v_to_v(NumOfVertices);
2498  GetVertexToVertexTable(v_to_v);
2499  STable3D *faces_tbl = GetFacesTable();
2500 
2501  if (Nodes) // curved mesh
2502  {
2503  UseTwoLevelState(1);
2504  }
2505 
2506  // call Mesh::HexUniformRefinement so that it won't update the nodes
2507  {
2508  GridFunction *nodes = Nodes;
2509  Nodes = NULL;
2511  Nodes = nodes;
2512  }
2513 
2514  // update the groups
2515  {
2516  int i, attr, newv[4], ind, m[5];
2517  Array<int> v;
2518 
2519  int group;
2520  Array<int> group_verts, group_edges, group_faces;
2521 
2522  int *I_group_svert, *J_group_svert;
2523  int *I_group_sedge, *J_group_sedge;
2524  int *I_group_sface, *J_group_sface;
2525 
2526  I_group_svert = new int[GetNGroups()+1];
2527  I_group_sedge = new int[GetNGroups()+1];
2528  I_group_sface = new int[GetNGroups()+1];
2529 
2530  I_group_svert[0] = I_group_svert[1] = 0;
2531  I_group_sedge[0] = I_group_sedge[1] = 0;
2532  I_group_sface[0] = I_group_sface[1] = 0;
2533 
2534  // compute the size of the J arrays
2535  J_group_svert = new int[group_svert.Size_of_connections()
2536  + group_sedge.Size_of_connections()
2537  + group_sface.Size_of_connections()];
2538  J_group_sedge = new int[2*group_sedge.Size_of_connections()
2539  + 4*group_sface.Size_of_connections()];
2540  J_group_sface = new int[4*group_sface.Size_of_connections()];
2541 
2542  for (group = 0; group < GetNGroups()-1; group++)
2543  {
2544  // Get the group shared objects
2545  group_svert.GetRow(group, group_verts);
2546  group_sedge.GetRow(group, group_edges);
2547  group_sface.GetRow(group, group_faces);
2548 
2549  // Process the edges that have been refined
2550  for (i = 0; i < group_sedge.RowSize(group); i++)
2551  {
2552  shared_edges[group_edges[i]]->GetVertices(v);
2553  ind = oedge + v_to_v(v[0], v[1]);
2554  // add a vertex
2555  group_verts.Append(svert_lvert.Append(ind)-1);
2556  // update the edges
2557  attr = shared_edges[group_edges[i]]->GetAttribute();
2558  shared_edges.Append(new Segment(v[1], ind, attr));
2559  group_edges.Append(sedge_ledge.Append(-1)-1);
2560  newv[0] = v[0]; newv[1] = ind;
2561  shared_edges[group_edges[i]]->SetVertices(newv);
2562  }
2563 
2564  // Process the faces that have been refined
2565  for (i = 0; i < group_sface.RowSize(group); i++)
2566  {
2567  shared_faces[group_faces[i]]->GetVertices(v);
2568  m[0] = oface+(*faces_tbl)(v[0], v[1], v[2], v[3]);
2569  // add a vertex
2570  group_verts.Append(svert_lvert.Append(m[0])-1);
2571  // add the refinement edges
2572  attr = shared_faces[group_faces[i]]->GetAttribute();
2573  m[1] = oedge + v_to_v(v[0], v[1]);
2574  m[2] = oedge + v_to_v(v[1], v[2]);
2575  m[3] = oedge + v_to_v(v[2], v[3]);
2576  m[4] = oedge + v_to_v(v[3], v[0]);
2577  shared_edges.Append(new Segment(m[1], m[0], attr));
2578  group_edges.Append(sedge_ledge.Append(-1)-1);
2579  shared_edges.Append(new Segment(m[2], m[0], attr));
2580  group_edges.Append(sedge_ledge.Append(-1)-1);
2581  shared_edges.Append(new Segment(m[3], m[0], attr));
2582  group_edges.Append(sedge_ledge.Append(-1)-1);
2583  shared_edges.Append(new Segment(m[4], m[0], attr));
2584  group_edges.Append(sedge_ledge.Append(-1)-1);
2585  // update faces
2586  newv[0] = v[0]; newv[1] = m[1]; newv[2] = m[0]; newv[3] = m[4];
2587  shared_faces[group_faces[i]]->SetVertices(newv);
2588  shared_faces.Append(new Quadrilateral(m[1],v[1],m[2],m[0],attr));
2589  group_faces.Append(sface_lface.Append(-1)-1);
2590  shared_faces.Append(new Quadrilateral(m[0],m[2],v[2],m[3],attr));
2591  group_faces.Append(sface_lface.Append(-1)-1);
2592  shared_faces.Append(new Quadrilateral(m[4],m[0],m[3],v[3],attr));
2593  group_faces.Append(sface_lface.Append(-1)-1);
2594  }
2595 
2596  I_group_svert[group+1] = I_group_svert[group] + group_verts.Size();
2597  I_group_sedge[group+1] = I_group_sedge[group] + group_edges.Size();
2598  I_group_sface[group+1] = I_group_sface[group] + group_faces.Size();
2599 
2600  int *J;
2601  J = J_group_svert+I_group_svert[group];
2602  for (i = 0; i < group_verts.Size(); i++)
2603  {
2604  J[i] = group_verts[i];
2605  }
2606  J = J_group_sedge+I_group_sedge[group];
2607  for (i = 0; i < group_edges.Size(); i++)
2608  {
2609  J[i] = group_edges[i];
2610  }
2611  J = J_group_sface+I_group_sface[group];
2612  for (i = 0; i < group_faces.Size(); i++)
2613  {
2614  J[i] = group_faces[i];
2615  }
2616  }
2617 
2618  // Fix the local numbers of shared edges and faces
2619  DSTable new_v_to_v(NumOfVertices);
2620  GetVertexToVertexTable(new_v_to_v);
2621  for (i = 0; i < shared_edges.Size(); i++)
2622  {
2623  shared_edges[i]->GetVertices(v);
2624  sedge_ledge[i] = new_v_to_v(v[0], v[1]);
2625  }
2626 
2627  delete faces_tbl;
2628  faces_tbl = GetFacesTable();
2629  for (i = 0; i < shared_faces.Size(); i++)
2630  {
2631  shared_faces[i]->GetVertices(v);
2632  sface_lface[i] = (*faces_tbl)(v[0], v[1], v[2], v[3]);
2633  }
2634  delete faces_tbl;
2635 
2636  group_svert.SetIJ(I_group_svert, J_group_svert);
2637  group_sedge.SetIJ(I_group_sedge, J_group_sedge);
2638  group_sface.SetIJ(I_group_sface, J_group_sface);
2639  }
2640 
2641  if (Nodes) // curved mesh
2642  {
2643  UpdateNodes();
2644  UseTwoLevelState(wtls);
2645  }
2646 }
2647 
2648 void ParMesh::NURBSUniformRefinement()
2649 {
2650  if (MyRank == 0)
2651  {
2652  cout << "\nParMesh::NURBSUniformRefinement : Not supported yet!\n";
2653  }
2654 }
2655 
2656 void ParMesh::PrintXG(std::ostream &out) const
2657 {
2658  MFEM_ASSERT(Dim == spaceDim, "2D manifolds not supported");
2659  if (Dim == 3 && meshgen == 1)
2660  {
2661  int i, j, nv;
2662  const int *ind;
2663 
2664  out << "NETGEN_Neutral_Format\n";
2665  // print the vertices
2666  out << NumOfVertices << '\n';
2667  for (i = 0; i < NumOfVertices; i++)
2668  {
2669  for (j = 0; j < Dim; j++)
2670  {
2671  out << " " << vertices[i](j);
2672  }
2673  out << '\n';
2674  }
2675 
2676  // print the elements
2677  out << NumOfElements << '\n';
2678  for (i = 0; i < NumOfElements; i++)
2679  {
2680  nv = elements[i]->GetNVertices();
2681  ind = elements[i]->GetVertices();
2682  out << elements[i]->GetAttribute();
2683  for (j = 0; j < nv; j++)
2684  {
2685  out << " " << ind[j]+1;
2686  }
2687  out << '\n';
2688  }
2689 
2690  // print the boundary + shared faces information
2691  out << NumOfBdrElements + shared_faces.Size() << '\n';
2692  // boundary
2693  for (i = 0; i < NumOfBdrElements; i++)
2694  {
2695  nv = boundary[i]->GetNVertices();
2696  ind = boundary[i]->GetVertices();
2697  out << boundary[i]->GetAttribute();
2698  for (j = 0; j < nv; j++)
2699  {
2700  out << " " << ind[j]+1;
2701  }
2702  out << '\n';
2703  }
2704  // shared faces
2705  for (i = 0; i < shared_faces.Size(); i++)
2706  {
2707  nv = shared_faces[i]->GetNVertices();
2708  ind = shared_faces[i]->GetVertices();
2709  out << shared_faces[i]->GetAttribute();
2710  for (j = 0; j < nv; j++)
2711  {
2712  out << " " << ind[j]+1;
2713  }
2714  out << '\n';
2715  }
2716  }
2717 
2718  if (Dim == 3 && meshgen == 2)
2719  {
2720  int i, j, nv;
2721  const int *ind;
2722 
2723  out << "TrueGrid\n"
2724  << "1 " << NumOfVertices << " " << NumOfElements << " 0 0 0 0 0 0 0\n"
2725  << "0 0 0 1 0 0 0 0 0 0 0\n"
2726  << "0 0 " << NumOfBdrElements+shared_faces.Size()
2727  << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
2728  << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
2729  << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
2730 
2731  // print the vertices
2732  for (i = 0; i < NumOfVertices; i++)
2733  out << i+1 << " 0.0 " << vertices[i](0) << " " << vertices[i](1)
2734  << " " << vertices[i](2) << " 0.0\n";
2735 
2736  // print the elements
2737  for (i = 0; i < NumOfElements; i++)
2738  {
2739  nv = elements[i]->GetNVertices();
2740  ind = elements[i]->GetVertices();
2741  out << i+1 << " " << elements[i]->GetAttribute();
2742  for (j = 0; j < nv; j++)
2743  {
2744  out << " " << ind[j]+1;
2745  }
2746  out << '\n';
2747  }
2748 
2749  // print the boundary information
2750  for (i = 0; i < NumOfBdrElements; i++)
2751  {
2752  nv = boundary[i]->GetNVertices();
2753  ind = boundary[i]->GetVertices();
2754  out << boundary[i]->GetAttribute();
2755  for (j = 0; j < nv; j++)
2756  {
2757  out << " " << ind[j]+1;
2758  }
2759  out << " 1.0 1.0 1.0 1.0\n";
2760  }
2761 
2762  // print the shared faces information
2763  for (i = 0; i < shared_faces.Size(); i++)
2764  {
2765  nv = shared_faces[i]->GetNVertices();
2766  ind = shared_faces[i]->GetVertices();
2767  out << shared_faces[i]->GetAttribute();
2768  for (j = 0; j < nv; j++)
2769  {
2770  out << " " << ind[j]+1;
2771  }
2772  out << " 1.0 1.0 1.0 1.0\n";
2773  }
2774  }
2775 
2776  if (Dim == 2)
2777  {
2778  int i, j, attr;
2779  Array<int> v;
2780 
2781  out << "areamesh2\n\n";
2782 
2783  // print the boundary + shared edges information
2784  out << NumOfBdrElements + shared_edges.Size() << '\n';
2785  // boundary
2786  for (i = 0; i < NumOfBdrElements; i++)
2787  {
2788  attr = boundary[i]->GetAttribute();
2789  boundary[i]->GetVertices(v);
2790  out << attr << " ";
2791  for (j = 0; j < v.Size(); j++)
2792  {
2793  out << v[j] + 1 << " ";
2794  }
2795  out << '\n';
2796  }
2797  // shared edges
2798  for (i = 0; i < shared_edges.Size(); i++)
2799  {
2800  attr = shared_edges[i]->GetAttribute();
2801  shared_edges[i]->GetVertices(v);
2802  out << attr << " ";
2803  for (j = 0; j < v.Size(); j++)
2804  {
2805  out << v[j] + 1 << " ";
2806  }
2807  out << '\n';
2808  }
2809 
2810  // print the elements
2811  out << NumOfElements << '\n';
2812  for (i = 0; i < NumOfElements; i++)
2813  {
2814  attr = elements[i]->GetAttribute();
2815  elements[i]->GetVertices(v);
2816 
2817  out << attr << " ";
2818  if ((j = GetElementType(i)) == Element::TRIANGLE)
2819  {
2820  out << 3 << " ";
2821  }
2822  else if (j == Element::QUADRILATERAL)
2823  {
2824  out << 4 << " ";
2825  }
2826  else if (j == Element::SEGMENT)
2827  {
2828  out << 2 << " ";
2829  }
2830  for (j = 0; j < v.Size(); j++)
2831  {
2832  out << v[j] + 1 << " ";
2833  }
2834  out << '\n';
2835  }
2836 
2837  // print the vertices
2838  out << NumOfVertices << '\n';
2839  for (i = 0; i < NumOfVertices; i++)
2840  {
2841  for (j = 0; j < Dim; j++)
2842  {
2843  out << vertices[i](j) << " ";
2844  }
2845  out << '\n';
2846  }
2847  }
2848 }
2849 
2850 void ParMesh::Print(std::ostream &out) const
2851 {
2852  bool print_shared = true;
2853  int i, j, shared_bdr_attr;
2854  Array<int> nc_shared_faces;
2855 
2856  const Array<int>* s2l_face;
2857  if (!pncmesh)
2858  {
2859  s2l_face = ((Dim == 1) ? &svert_lvert :
2860  ((Dim == 2) ? &sedge_ledge : &sface_lface));
2861  }
2862  else
2863  {
2864  s2l_face = &nc_shared_faces;
2865  if (Dim >= 2)
2866  {
2867  // get a list of all shared non-ghost faces
2868  const NCMesh::NCList& sfaces =
2869  (Dim == 3) ? pncmesh->GetSharedFaces() : pncmesh->GetSharedEdges();
2870  const int nfaces = GetNumFaces();
2871  for (unsigned i = 0; i < sfaces.conforming.size(); i++)
2872  {
2873  int index = sfaces.conforming[i].index;
2874  if (index < nfaces) { nc_shared_faces.Append(index); }
2875  }
2876  for (unsigned i = 0; i < sfaces.masters.size(); i++)
2877  {
2878  int index = sfaces.masters[i].index;
2879  if (index < nfaces) { nc_shared_faces.Append(index); }
2880  }
2881  for (unsigned i = 0; i < sfaces.slaves.size(); i++)
2882  {
2883  int index = sfaces.slaves[i].index;
2884  if (index < nfaces) { nc_shared_faces.Append(index); }
2885  }
2886  }
2887  }
2888 
2889  if (NURBSext)
2890  {
2891  Mesh::Print(out); // does not print shared boundary
2892  return;
2893  }
2894 
2895  out << "MFEM mesh v1.0\n";
2896 
2897  // optional
2898  out <<
2899  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
2900  "# POINT = 0\n"
2901  "# SEGMENT = 1\n"
2902  "# TRIANGLE = 2\n"
2903  "# SQUARE = 3\n"
2904  "# TETRAHEDRON = 4\n"
2905  "# CUBE = 5\n"
2906  "#\n";
2907 
2908  out << "\ndimension\n" << Dim
2909  << "\n\nelements\n" << NumOfElements << '\n';
2910  for (i = 0; i < NumOfElements; i++)
2911  {
2912  PrintElement(elements[i], out);
2913  }
2914 
2915  int num_bdr_elems = NumOfBdrElements;
2916  if (print_shared && Dim > 1)
2917  {
2918  num_bdr_elems += s2l_face->Size();
2919  }
2920  out << "\nboundary\n" << num_bdr_elems << '\n';
2921  for (i = 0; i < NumOfBdrElements; i++)
2922  {
2923  PrintElement(boundary[i], out);
2924  }
2925 
2926  if (print_shared && Dim > 1)
2927  {
2928  if (bdr_attributes.Size())
2929  {
2930  shared_bdr_attr = bdr_attributes.Max() + MyRank + 1;
2931  }
2932  else
2933  {
2934  shared_bdr_attr = MyRank + 1;
2935  }
2936  for (i = 0; i < s2l_face->Size(); i++)
2937  {
2938  // Modify the attributes of the faces (not used otherwise?)
2939  faces[(*s2l_face)[i]]->SetAttribute(shared_bdr_attr);
2940  PrintElement(faces[(*s2l_face)[i]], out);
2941  }
2942  }
2943  out << "\nvertices\n" << NumOfVertices << '\n';
2944  if (Nodes == NULL)
2945  {
2946  out << spaceDim << '\n';
2947  for (i = 0; i < NumOfVertices; i++)
2948  {
2949  out << vertices[i](0);
2950  for (j = 1; j < spaceDim; j++)
2951  {
2952  out << ' ' << vertices[i](j);
2953  }
2954  out << '\n';
2955  }
2956  }
2957  else
2958  {
2959  out << "\nnodes\n";
2960  Nodes->Save(out);
2961  }
2962 }
2963 
2964 static void dump_element(const Element* elem, Array<int> &data)
2965 {
2966  data.Append(elem->GetGeometryType());
2967 
2968  int nv = elem->GetNVertices();
2969  const int *v = elem->GetVertices();
2970  for (int i = 0; i < nv; i++)
2971  {
2972  data.Append(v[i]);
2973  }
2974 }
2975 
2976 void ParMesh::PrintAsOne(std::ostream &out)
2977 {
2978  int i, j, k, p, nv_ne[2], &nv = nv_ne[0], &ne = nv_ne[1], vc;
2979  const int *v;
2980  MPI_Status status;
2981  Array<double> vert;
2982  Array<int> ints;
2983 
2984  if (MyRank == 0)
2985  {
2986  out << "MFEM mesh v1.0\n";
2987 
2988  // optional
2989  out <<
2990  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
2991  "# POINT = 0\n"
2992  "# SEGMENT = 1\n"
2993  "# TRIANGLE = 2\n"
2994  "# SQUARE = 3\n"
2995  "# TETRAHEDRON = 4\n"
2996  "# CUBE = 5\n"
2997  "#\n";
2998 
2999  out << "\ndimension\n" << Dim;
3000  }
3001 
3002  nv = NumOfElements;
3003  MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm);
3004  if (MyRank == 0)
3005  {
3006  out << "\n\nelements\n" << ne << '\n';
3007  for (i = 0; i < NumOfElements; i++)
3008  {
3009  // processor number + 1 as attribute and geometry type
3010  out << 1 << ' ' << elements[i]->GetGeometryType();
3011  // vertices
3012  nv = elements[i]->GetNVertices();
3013  v = elements[i]->GetVertices();
3014  for (j = 0; j < nv; j++)
3015  {
3016  out << ' ' << v[j];
3017  }
3018  out << '\n';
3019  }
3020  vc = NumOfVertices;
3021  for (p = 1; p < NRanks; p++)
3022  {
3023  MPI_Recv(nv_ne, 2, MPI_INT, p, 444, MyComm, &status);
3024  ints.SetSize(ne);
3025  MPI_Recv(&ints[0], ne, MPI_INT, p, 445, MyComm, &status);
3026  for (i = 0; i < ne; )
3027  {
3028  // processor number + 1 as attribute and geometry type
3029  out << p+1 << ' ' << ints[i];
3030  // vertices
3031  k = Geometries.GetVertices(ints[i++])->GetNPoints();
3032  for (j = 0; j < k; j++)
3033  {
3034  out << ' ' << vc + ints[i++];
3035  }
3036  out << '\n';
3037  }
3038  vc += nv;
3039  }
3040  }
3041  else
3042  {
3043  // for each element send its geometry type and its vertices
3044  ne = 0;
3045  for (i = 0; i < NumOfElements; i++)
3046  {
3047  ne += 1 + elements[i]->GetNVertices();
3048  }
3049  nv = NumOfVertices;
3050  MPI_Send(nv_ne, 2, MPI_INT, 0, 444, MyComm);
3051 
3052  ints.Reserve(ne);
3053  ints.SetSize(0);
3054  for (i = 0; i < NumOfElements; i++)
3055  {
3056  dump_element(elements[i], ints);
3057  }
3058  MFEM_ASSERT(ints.Size() == ne, "");
3059  MPI_Send(&ints[0], ne, MPI_INT, 0, 445, MyComm);
3060  }
3061 
3062  // boundary + shared boundary
3063  ne = NumOfBdrElements;
3064  if (!pncmesh)
3065  {
3066  ne += ((Dim == 2) ? shared_edges : shared_faces).Size();
3067  }
3068  else if (Dim > 1)
3069  {
3070  const NCMesh::NCList &list = pncmesh->GetSharedList(Dim - 1);
3071  ne += list.conforming.size() + list.masters.size() + list.slaves.size();
3072  }
3073  ints.Reserve(ne * (1 + 2*(Dim-1))); // just an upper bound
3074  ints.SetSize(0);
3075 
3076  // for each boundary and shared boundary element send its geometry type
3077  // and its vertices
3078  ne = 0;
3079  for (i = j = 0; i < NumOfBdrElements; i++)
3080  {
3081  dump_element(boundary[i], ints); ne++;
3082  }
3083  if (!pncmesh)
3084  {
3085  Array<Element*> &shared = (Dim == 2) ? shared_edges : shared_faces;
3086  for (i = 0; i < shared.Size(); i++)
3087  {
3088  dump_element(shared[i], ints); ne++;
3089  }
3090  }
3091  else if (Dim > 1)
3092  {
3093  const NCMesh::NCList &list = pncmesh->GetSharedList(Dim - 1);
3094  const int nfaces = GetNumFaces();
3095  for (i = 0; i < (int) list.conforming.size(); i++)
3096  {
3097  int index = list.conforming[i].index;
3098  if (index < nfaces) { dump_element(faces[index], ints); ne++; }
3099  }
3100  for (i = 0; i < (int) list.masters.size(); i++)
3101  {
3102  int index = list.masters[i].index;
3103  if (index < nfaces) { dump_element(faces[index], ints); ne++; }
3104  }
3105  for (i = 0; i < (int) list.slaves.size(); i++)
3106  {
3107  int index = list.slaves[i].index;
3108  if (index < nfaces) { dump_element(faces[index], ints); ne++; }
3109  }
3110  }
3111 
3112  MPI_Reduce(&ne, &k, 1, MPI_INT, MPI_SUM, 0, MyComm);
3113  if (MyRank == 0)
3114  {
3115  out << "\nboundary\n" << k << '\n';
3116  vc = 0;
3117  for (p = 0; p < NRanks; p++)
3118  {
3119  if (p)
3120  {
3121  MPI_Recv(nv_ne, 2, MPI_INT, p, 446, MyComm, &status);
3122  ints.SetSize(ne);
3123  MPI_Recv(ints.GetData(), ne, MPI_INT, p, 447, MyComm, &status);
3124  }
3125  else
3126  {
3127  ne = ints.Size();
3128  nv = NumOfVertices;
3129  }
3130  for (i = 0; i < ne; )
3131  {
3132  // processor number + 1 as bdr. attr. and bdr. geometry type
3133  out << p+1 << ' ' << ints[i];
3134  k = Geometries.GetVertices(ints[i++])->GetNPoints();
3135  // vertices
3136  for (j = 0; j < k; j++)
3137  {
3138  out << ' ' << vc + ints[i++];
3139  }
3140  out << '\n';
3141  }
3142  vc += nv;
3143  }
3144  }
3145  else
3146  {
3147  nv = NumOfVertices;
3148  ne = ints.Size();
3149  MPI_Send(nv_ne, 2, MPI_INT, 0, 446, MyComm);
3150  MPI_Send(ints.GetData(), ne, MPI_INT, 0, 447, MyComm);
3151  }
3152 
3153  // vertices / nodes
3154  MPI_Reduce(&NumOfVertices, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm);
3155  if (MyRank == 0)
3156  {
3157  out << "\nvertices\n" << nv << '\n';
3158  }
3159  if (Nodes == NULL)
3160  {
3161  if (MyRank == 0)
3162  {
3163  out << spaceDim << '\n';
3164  for (i = 0; i < NumOfVertices; i++)
3165  {
3166  out << vertices[i](0);
3167  for (j = 1; j < spaceDim; j++)
3168  {
3169  out << ' ' << vertices[i](j);
3170  }
3171  out << '\n';
3172  }
3173  for (p = 1; p < NRanks; p++)
3174  {
3175  MPI_Recv(&nv, 1, MPI_INT, p, 448, MyComm, &status);
3176  vert.SetSize(nv*spaceDim);
3177  MPI_Recv(&vert[0], nv*spaceDim, MPI_DOUBLE, p, 449, MyComm, &status);
3178  for (i = 0; i < nv; i++)
3179  {
3180  out << vert[i*spaceDim];
3181  for (j = 1; j < spaceDim; j++)
3182  {
3183  out << ' ' << vert[i*spaceDim+j];
3184  }
3185  out << '\n';
3186  }
3187  }
3188  }
3189  else
3190  {
3191  MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 448, MyComm);
3192  vert.SetSize(NumOfVertices*spaceDim);
3193  for (i = 0; i < NumOfVertices; i++)
3194  {
3195  for (j = 0; j < spaceDim; j++)
3196  {
3197  vert[i*spaceDim+j] = vertices[i](j);
3198  }
3199  }
3200  MPI_Send(&vert[0], NumOfVertices*spaceDim, MPI_DOUBLE, 0, 449, MyComm);
3201  }
3202  }
3203  else
3204  {
3205  if (MyRank == 0)
3206  {
3207  out << "\nnodes\n";
3208  }
3209  ParGridFunction *pnodes = dynamic_cast<ParGridFunction *>(Nodes);
3210  if (pnodes)
3211  {
3212  pnodes->SaveAsOne(out);
3213  }
3214  else
3215  {
3216  ParFiniteElementSpace *pfes =
3217  dynamic_cast<ParFiniteElementSpace *>(Nodes->FESpace());
3218  if (pfes)
3219  {
3220  // create a wrapper ParGridFunction
3221  ParGridFunction ParNodes(pfes, Nodes);
3222  ParNodes.SaveAsOne(out);
3223  }
3224  else
3225  {
3226  mfem_error("ParMesh::PrintAsOne : Nodes have no parallel info!");
3227  }
3228  }
3229  }
3230 }
3231 
3232 void ParMesh::PrintAsOneXG(std::ostream &out)
3233 {
3234  MFEM_ASSERT(Dim == spaceDim, "2D Manifolds not supported.");
3235  if (Dim == 3 && meshgen == 1)
3236  {
3237  int i, j, k, nv, ne, p;
3238  const int *ind, *v;
3239  MPI_Status status;
3240  Array<double> vert;
3241  Array<int> ints;
3242 
3243  if (MyRank == 0)
3244  {
3245  out << "NETGEN_Neutral_Format\n";
3246  // print the vertices
3247  ne = NumOfVertices;
3248  MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm);
3249  out << nv << '\n';
3250  for (i = 0; i < NumOfVertices; i++)
3251  {
3252  for (j = 0; j < Dim; j++)
3253  {
3254  out << " " << vertices[i](j);
3255  }
3256  out << '\n';
3257  }
3258  for (p = 1; p < NRanks; p++)
3259  {
3260  MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status);
3261  vert.SetSize(Dim*nv);
3262  MPI_Recv(&vert[0], Dim*nv, MPI_DOUBLE, p, 445, MyComm, &status);
3263  for (i = 0; i < nv; i++)
3264  {
3265  for (j = 0; j < Dim; j++)
3266  {
3267  out << " " << vert[Dim*i+j];
3268  }
3269  out << '\n';
3270  }
3271  }
3272 
3273  // print the elements
3274  nv = NumOfElements;
3275  MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm);
3276  out << ne << '\n';
3277  for (i = 0; i < NumOfElements; i++)
3278  {
3279  nv = elements[i]->GetNVertices();
3280  ind = elements[i]->GetVertices();
3281  out << 1;
3282  for (j = 0; j < nv; j++)
3283  {
3284  out << " " << ind[j]+1;
3285  }
3286  out << '\n';
3287  }
3288  k = NumOfVertices;
3289  for (p = 1; p < NRanks; p++)
3290  {
3291  MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status);
3292  MPI_Recv(&ne, 1, MPI_INT, p, 446, MyComm, &status);
3293  ints.SetSize(4*ne);
3294  MPI_Recv(&ints[0], 4*ne, MPI_INT, p, 447, MyComm, &status);
3295  for (i = 0; i < ne; i++)
3296  {
3297  out << p+1;
3298  for (j = 0; j < 4; j++)
3299  {
3300  out << " " << k+ints[i*4+j]+1;
3301  }
3302  out << '\n';
3303  }
3304  k += nv;
3305  }
3306  // print the boundary + shared faces information
3307  nv = NumOfBdrElements + shared_faces.Size();
3308  MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm);
3309  out << ne << '\n';
3310  // boundary
3311  for (i = 0; i < NumOfBdrElements; i++)
3312  {
3313  nv = boundary[i]->GetNVertices();
3314  ind = boundary[i]->GetVertices();
3315  out << 1;
3316  for (j = 0; j < nv; j++)
3317  {
3318  out << " " << ind[j]+1;
3319  }
3320  out << '\n';
3321  }
3322  // shared faces
3323  for (i = 0; i < shared_faces.Size(); i++)
3324  {
3325  nv = shared_faces[i]->GetNVertices();
3326  ind = shared_faces[i]->GetVertices();
3327  out << 1;
3328  for (j = 0; j < nv; j++)
3329  {
3330  out << " " << ind[j]+1;
3331  }
3332  out << '\n';
3333  }
3334  k = NumOfVertices;
3335  for (p = 1; p < NRanks; p++)
3336  {
3337  MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status);
3338  MPI_Recv(&ne, 1, MPI_INT, p, 446, MyComm, &status);
3339  ints.SetSize(3*ne);
3340  MPI_Recv(&ints[0], 3*ne, MPI_INT, p, 447, MyComm, &status);
3341  for (i = 0; i < ne; i++)
3342  {
3343  out << p+1;
3344  for (j = 0; j < 3; j++)
3345  {
3346  out << " " << k+ints[i*3+j]+1;
3347  }
3348  out << '\n';
3349  }
3350  k += nv;
3351  }
3352  }
3353  else
3354  {
3355  ne = NumOfVertices;
3356  MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm);
3357  MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm);
3358  vert.SetSize(Dim*NumOfVertices);
3359  for (i = 0; i < NumOfVertices; i++)
3360  for (j = 0; j < Dim; j++)
3361  {
3362  vert[Dim*i+j] = vertices[i](j);
3363  }
3364  MPI_Send(&vert[0], Dim*NumOfVertices, MPI_DOUBLE,
3365  0, 445, MyComm);
3366  // elements
3367  ne = NumOfElements;
3368  MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm);
3369  MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm);
3370  MPI_Send(&NumOfElements, 1, MPI_INT, 0, 446, MyComm);
3371  ints.SetSize(NumOfElements*4);
3372  for (i = 0; i < NumOfElements; i++)
3373  {
3374  v = elements[i]->GetVertices();
3375  for (j = 0; j < 4; j++)
3376  {
3377  ints[4*i+j] = v[j];
3378  }
3379  }
3380  MPI_Send(&ints[0], 4*NumOfElements, MPI_INT, 0, 447, MyComm);
3381  // boundary + shared faces
3382  nv = NumOfBdrElements + shared_faces.Size();
3383  MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm);
3384  MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm);
3385  ne = NumOfBdrElements + shared_faces.Size();
3386  MPI_Send(&ne, 1, MPI_INT, 0, 446, MyComm);
3387  ints.SetSize(3*ne);
3388  for (i = 0; i < NumOfBdrElements; i++)
3389  {
3390  v = boundary[i]->GetVertices();
3391  for (j = 0; j < 3; j++)
3392  {
3393  ints[3*i+j] = v[j];
3394  }
3395  }
3396  for ( ; i < ne; i++)
3397  {
3398  v = shared_faces[i-NumOfBdrElements]->GetVertices();
3399  for (j = 0; j < 3; j++)
3400  {
3401  ints[3*i+j] = v[j];
3402  }
3403  }
3404  MPI_Send(&ints[0], 3*ne, MPI_INT, 0, 447, MyComm);
3405  }
3406  }
3407 
3408  if (Dim == 3 && meshgen == 2)
3409  {
3410  int i, j, k, nv, ne, p;
3411  const int *ind, *v;
3412  MPI_Status status;
3413  Array<double> vert;
3414  Array<int> ints;
3415 
3416  int TG_nv, TG_ne, TG_nbe;
3417 
3418  if (MyRank == 0)
3419  {
3420  MPI_Reduce(&NumOfVertices, &TG_nv, 1, MPI_INT, MPI_SUM, 0, MyComm);
3421  MPI_Reduce(&NumOfElements, &TG_ne, 1, MPI_INT, MPI_SUM, 0, MyComm);
3422  nv = NumOfBdrElements + shared_faces.Size();
3423  MPI_Reduce(&nv, &TG_nbe, 1, MPI_INT, MPI_SUM, 0, MyComm);
3424 
3425  out << "TrueGrid\n"
3426  << "1 " << TG_nv << " " << TG_ne << " 0 0 0 0 0 0 0\n"
3427  << "0 0 0 1 0 0 0 0 0 0 0\n"
3428  << "0 0 " << TG_nbe << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
3429  << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
3430  << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
3431 
3432  // print the vertices
3433  nv = TG_nv;
3434  for (i = 0; i < NumOfVertices; i++)
3435  out << i+1 << " 0.0 " << vertices[i](0) << " " << vertices[i](1)
3436  << " " << vertices[i](2) << " 0.0\n";
3437  for (p = 1; p < NRanks; p++)
3438  {
3439  MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status);
3440  vert.SetSize(Dim*nv);
3441  MPI_Recv(&vert[0], Dim*nv, MPI_DOUBLE, p, 445, MyComm, &status);
3442  for (i = 0; i < nv; i++)
3443  out << i+1 << " 0.0 " << vert[Dim*i] << " " << vert[Dim*i+1]
3444  << " " << vert[Dim*i+2] << " 0.0\n";
3445  }
3446 
3447  // print the elements
3448  ne = TG_ne;
3449  for (i = 0; i < NumOfElements; i++)
3450  {
3451  nv = elements[i]->GetNVertices();
3452  ind = elements[i]->GetVertices();
3453  out << i+1 << " " << 1;
3454  for (j = 0; j < nv; j++)
3455  {
3456  out << " " << ind[j]+1;
3457  }
3458  out << '\n';
3459  }
3460  k = NumOfVertices;
3461  for (p = 1; p < NRanks; p++)
3462  {
3463  MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status);
3464  MPI_Recv(&ne, 1, MPI_INT, p, 446, MyComm, &status);
3465  ints.SetSize(8*ne);
3466  MPI_Recv(&ints[0], 8*ne, MPI_INT, p, 447, MyComm, &status);
3467  for (i = 0; i < ne; i++)
3468  {
3469  out << i+1 << " " << p+1;
3470  for (j = 0; j < 8; j++)
3471  {
3472  out << " " << k+ints[i*8+j]+1;
3473  }
3474  out << '\n';
3475  }
3476  k += nv;
3477  }
3478 
3479  // print the boundary + shared faces information
3480  ne = TG_nbe;
3481  // boundary
3482  for (i = 0; i < NumOfBdrElements; i++)
3483  {
3484  nv = boundary[i]->GetNVertices();
3485  ind = boundary[i]->GetVertices();
3486  out << 1;
3487  for (j = 0; j < nv; j++)
3488  {
3489  out << " " << ind[j]+1;
3490  }
3491  out << " 1.0 1.0 1.0 1.0\n";
3492  }
3493  // shared faces
3494  for (i = 0; i < shared_faces.Size(); i++)
3495  {
3496  nv = shared_faces[i]->GetNVertices();
3497  ind = shared_faces[i]->GetVertices();
3498  out << 1;
3499  for (j = 0; j < nv; j++)
3500  {
3501  out << " " << ind[j]+1;
3502  }
3503  out << " 1.0 1.0 1.0 1.0\n";
3504  }
3505  k = NumOfVertices;
3506  for (p = 1; p < NRanks; p++)
3507  {
3508  MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status);
3509  MPI_Recv(&ne, 1, MPI_INT, p, 446, MyComm, &status);
3510  ints.SetSize(4*ne);
3511  MPI_Recv(&ints[0], 4*ne, MPI_INT, p, 447, MyComm, &status);
3512  for (i = 0; i < ne; i++)
3513  {
3514  out << p+1;
3515  for (j = 0; j < 4; j++)
3516  {
3517  out << " " << k+ints[i*4+j]+1;
3518  }
3519  out << " 1.0 1.0 1.0 1.0\n";
3520  }
3521  k += nv;
3522  }
3523  }
3524  else
3525  {
3526  MPI_Reduce(&NumOfVertices, &TG_nv, 1, MPI_INT, MPI_SUM, 0, MyComm);
3527  MPI_Reduce(&NumOfElements, &TG_ne, 1, MPI_INT, MPI_SUM, 0, MyComm);
3528  nv = NumOfBdrElements + shared_faces.Size();
3529  MPI_Reduce(&nv, &TG_nbe, 1, MPI_INT, MPI_SUM, 0, MyComm);
3530 
3531  MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm);
3532  vert.SetSize(Dim*NumOfVertices);
3533  for (i = 0; i < NumOfVertices; i++)
3534  for (j = 0; j < Dim; j++)
3535  {
3536  vert[Dim*i+j] = vertices[i](j);
3537  }
3538  MPI_Send(&vert[0], Dim*NumOfVertices, MPI_DOUBLE, 0, 445, MyComm);
3539  // elements
3540  MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm);
3541  MPI_Send(&NumOfElements, 1, MPI_INT, 0, 446, MyComm);
3542  ints.SetSize(NumOfElements*8);
3543  for (i = 0; i < NumOfElements; i++)
3544  {
3545  v = elements[i]->GetVertices();
3546  for (j = 0; j < 8; j++)
3547  {
3548  ints[8*i+j] = v[j];
3549  }
3550  }
3551  MPI_Send(&ints[0], 8*NumOfElements, MPI_INT, 0, 447, MyComm);
3552  // boundary + shared faces
3553  MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm);
3554  ne = NumOfBdrElements + shared_faces.Size();
3555  MPI_Send(&ne, 1, MPI_INT, 0, 446, MyComm);
3556  ints.SetSize(4*ne);
3557  for (i = 0; i < NumOfBdrElements; i++)
3558  {
3559  v = boundary[i]->GetVertices();
3560  for (j = 0; j < 4; j++)
3561  {
3562  ints[4*i+j] = v[j];
3563  }
3564  }
3565  for ( ; i < ne; i++)
3566  {
3567  v = shared_faces[i-NumOfBdrElements]->GetVertices();
3568  for (j = 0; j < 4; j++)
3569  {
3570  ints[4*i+j] = v[j];
3571  }
3572  }
3573  MPI_Send(&ints[0], 4*ne, MPI_INT, 0, 447, MyComm);
3574  }
3575  }
3576 
3577  if (Dim == 2)
3578  {
3579  int i, j, k, attr, nv, ne, p;
3580  Array<int> v;
3581  MPI_Status status;
3582  Array<double> vert;
3583  Array<int> ints;
3584 
3585 
3586  if (MyRank == 0)
3587  {
3588  out << "areamesh2\n\n";
3589 
3590  // print the boundary + shared edges information
3591  nv = NumOfBdrElements + shared_edges.Size();
3592  MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm);
3593  out << ne << '\n';
3594  // boundary
3595  for (i = 0; i < NumOfBdrElements; i++)
3596  {
3597  attr = boundary[i]->GetAttribute();
3598  boundary[i]->GetVertices(v);
3599  out << attr << " ";
3600  for (j = 0; j < v.Size(); j++)
3601  {
3602  out << v[j] + 1 << " ";
3603  }
3604  out << '\n';
3605  }
3606  // shared edges
3607  for (i = 0; i < shared_edges.Size(); i++)
3608  {
3609  attr = shared_edges[i]->GetAttribute();
3610  shared_edges[i]->GetVertices(v);
3611  out << attr << " ";
3612  for (j = 0; j < v.Size(); j++)
3613  {
3614  out << v[j] + 1 << " ";
3615  }
3616  out << '\n';
3617  }
3618  k = NumOfVertices;
3619  for (p = 1; p < NRanks; p++)
3620  {
3621  MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status);
3622  MPI_Recv(&ne, 1, MPI_INT, p, 446, MyComm, &status);
3623  ints.SetSize(2*ne);
3624  MPI_Recv(&ints[0], 2*ne, MPI_INT, p, 447, MyComm, &status);
3625  for (i = 0; i < ne; i++)
3626  {
3627  out << p+1;
3628  for (j = 0; j < 2; j++)
3629  {
3630  out << " " << k+ints[i*2+j]+1;
3631  }
3632  out << '\n';
3633  }
3634  k += nv;
3635  }
3636 
3637  // print the elements
3638  nv = NumOfElements;
3639  MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm);
3640  out << ne << '\n';
3641  for (i = 0; i < NumOfElements; i++)
3642  {
3643  attr = elements[i]->GetAttribute();
3644  elements[i]->GetVertices(v);
3645  out << 1 << " " << 3 << " ";
3646  for (j = 0; j < v.Size(); j++)
3647  {
3648  out << v[j] + 1 << " ";
3649  }
3650  out << '\n';
3651  }
3652  k = NumOfVertices;
3653  for (p = 1; p < NRanks; p++)
3654  {
3655  MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status);
3656  MPI_Recv(&ne, 1, MPI_INT, p, 446, MyComm, &status);
3657  ints.SetSize(3*ne);
3658  MPI_Recv(&ints[0], 3*ne, MPI_INT, p, 447, MyComm, &status);
3659  for (i = 0; i < ne; i++)
3660  {
3661  out << p+1 << " " << 3;
3662  for (j = 0; j < 3; j++)
3663  {
3664  out << " " << k+ints[i*3+j]+1;
3665  }
3666  out << '\n';
3667  }
3668  k += nv;
3669  }
3670 
3671  // print the vertices
3672  ne = NumOfVertices;
3673  MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm);
3674  out << nv << '\n';
3675  for (i = 0; i < NumOfVertices; i++)
3676  {
3677  for (j = 0; j < Dim; j++)
3678  {
3679  out << vertices[i](j) << " ";
3680  }
3681  out << '\n';
3682  }
3683  for (p = 1; p < NRanks; p++)
3684  {
3685  MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status);
3686  vert.SetSize(Dim*nv);
3687  MPI_Recv(&vert[0], Dim*nv, MPI_DOUBLE, p, 445, MyComm, &status);
3688  for (i = 0; i < nv; i++)
3689  {
3690  for (j = 0; j < Dim; j++)
3691  {
3692  out << " " << vert[Dim*i+j];
3693  }
3694  out << '\n';
3695  }
3696  }
3697  }
3698  else
3699  {
3700  // boundary + shared faces
3701  nv = NumOfBdrElements + shared_edges.Size();
3702  MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm);
3703  MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm);
3704  ne = NumOfBdrElements + shared_edges.Size();
3705  MPI_Send(&ne, 1, MPI_INT, 0, 446, MyComm);
3706  ints.SetSize(2*ne);
3707  for (i = 0; i < NumOfBdrElements; i++)
3708  {
3709  boundary[i]->GetVertices(v);
3710  for (j = 0; j < 2; j++)
3711  {
3712  ints[2*i+j] = v[j];
3713  }
3714  }
3715  for ( ; i < ne; i++)
3716  {
3717  shared_edges[i-NumOfBdrElements]->GetVertices(v);
3718  for (j = 0; j < 2; j++)
3719  {
3720  ints[2*i+j] = v[j];
3721  }
3722  }
3723  MPI_Send(&ints[0], 2*ne, MPI_INT, 0, 447, MyComm);
3724  // elements
3725  ne = NumOfElements;
3726  MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm);
3727  MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm);
3728  MPI_Send(&NumOfElements, 1, MPI_INT, 0, 446, MyComm);
3729  ints.SetSize(NumOfElements*3);
3730  for (i = 0; i < NumOfElements; i++)
3731  {
3732  elements[i]->GetVertices(v);
3733  for (j = 0; j < 3; j++)
3734  {
3735  ints[3*i+j] = v[j];
3736  }
3737  }
3738  MPI_Send(&ints[0], 3*NumOfElements, MPI_INT, 0, 447, MyComm);
3739  // vertices
3740  ne = NumOfVertices;
3741  MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm);
3742  MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm);
3743  vert.SetSize(Dim*NumOfVertices);
3744  for (i = 0; i < NumOfVertices; i++)
3745  for (j = 0; j < Dim; j++)
3746  {
3747  vert[Dim*i+j] = vertices[i](j);
3748  }
3749  MPI_Send(&vert[0], Dim*NumOfVertices, MPI_DOUBLE,
3750  0, 445, MyComm);
3751  }
3752  }
3753 }
3754 
3755 void ParMesh::PrintInfo(std::ostream &out)
3756 {
3757  int i;
3758  DenseMatrix J(Dim);
3759  double h_min, h_max, kappa_min, kappa_max, h, kappa;
3760 
3761  if (MyRank == 0)
3762  {
3763  out << "Parallel Mesh Stats:" << '\n';
3764  }
3765 
3766  for (i = 0; i < NumOfElements; i++)
3767  {
3768  GetElementJacobian(i, J);
3769  h = pow(fabs(J.Det()), 1.0/double(Dim));
3770  kappa = J.CalcSingularvalue(0) / J.CalcSingularvalue(Dim-1);
3771  if (i == 0)
3772  {
3773  h_min = h_max = h;
3774  kappa_min = kappa_max = kappa;
3775  }
3776  else
3777  {
3778  if (h < h_min) { h_min = h; }
3779  if (h > h_max) { h_max = h; }
3780  if (kappa < kappa_min) { kappa_min = kappa; }
3781  if (kappa > kappa_max) { kappa_max = kappa; }
3782  }
3783  }
3784 
3785  double gh_min, gh_max, gk_min, gk_max;
3786  MPI_Reduce(&h_min, &gh_min, 1, MPI_DOUBLE, MPI_MIN, 0, MyComm);
3787  MPI_Reduce(&h_max, &gh_max, 1, MPI_DOUBLE, MPI_MAX, 0, MyComm);
3788  MPI_Reduce(&kappa_min, &gk_min, 1, MPI_DOUBLE, MPI_MIN, 0, MyComm);
3789  MPI_Reduce(&kappa_max, &gk_max, 1, MPI_DOUBLE, MPI_MAX, 0, MyComm);
3790 
3791  long ldata[5]; // vert, edge, face, elem, neighbors;
3792  long mindata[5], maxdata[5], sumdata[5];
3793 
3794  // count locally owned vertices, edges, and faces
3795  ldata[0] = GetNV();
3796  ldata[1] = GetNEdges();
3797  ldata[2] = GetNFaces();
3798  ldata[3] = GetNE();
3799  ldata[4] = gtopo.GetNumNeighbors()-1;
3800  for (int gr = 1; gr < GetNGroups(); gr++)
3801  if (!gtopo.IAmMaster(gr)) // we are not the master
3802  {
3803  ldata[0] -= group_svert.RowSize(gr-1);
3804  ldata[1] -= group_sedge.RowSize(gr-1);
3805  ldata[2] -= group_sface.RowSize(gr-1);
3806  }
3807 
3808  MPI_Reduce(ldata, mindata, 5, MPI_LONG, MPI_MIN, 0, MyComm);
3809  MPI_Reduce(ldata, sumdata, 5, MPI_LONG, MPI_SUM, 0, MyComm);
3810  MPI_Reduce(ldata, maxdata, 5, MPI_LONG, MPI_MAX, 0, MyComm);
3811 
3812  if (MyRank == 0)
3813  {
3814  out << '\n'
3815  << " "
3816  << setw(12) << "minimum"
3817  << setw(12) << "average"
3818  << setw(12) << "maximum"
3819  << setw(12) << "total" << '\n';
3820  out << " vertices "
3821  << setw(12) << mindata[0]
3822  << setw(12) << sumdata[0]/NRanks
3823  << setw(12) << maxdata[0]
3824  << setw(12) << sumdata[0] << '\n';
3825  out << " edges "
3826  << setw(12) << mindata[1]
3827  << setw(12) << sumdata[1]/NRanks
3828  << setw(12) << maxdata[1]
3829  << setw(12) << sumdata[1] << '\n';
3830  if (Dim == 3)
3831  out << " faces "
3832  << setw(12) << mindata[2]
3833  << setw(12) << sumdata[2]/NRanks
3834  << setw(12) << maxdata[2]
3835  << setw(12) << sumdata[2] << '\n';
3836  out << " elements "
3837  << setw(12) << mindata[3]
3838  << setw(12) << sumdata[3]/NRanks
3839  << setw(12) << maxdata[3]
3840  << setw(12) << sumdata[3] << '\n';
3841  out << " neighbors "
3842  << setw(12) << mindata[4]
3843  << setw(12) << sumdata[4]/NRanks
3844  << setw(12) << maxdata[4] << '\n';
3845  out << '\n'
3846  << " "
3847  << setw(12) << "minimum"
3848  << setw(12) << "maximum" << '\n';
3849  out << " h "
3850  << setw(12) << gh_min
3851  << setw(12) << gh_max << '\n';
3852  out << " kappa "
3853  << setw(12) << gk_min
3854  << setw(12) << gk_max << '\n';
3855  out << std::flush;
3856  }
3857 }
3858 
3860 {
3862 
3863  delete pncmesh;
3864  ncmesh = pncmesh = NULL;
3865 
3866  DeleteFaceNbrData();
3867 
3868  for (int i = 0; i < shared_faces.Size(); i++)
3869  {
3870  FreeElement(shared_faces[i]);
3871  }
3872  for (int i = 0; i < shared_edges.Size(); i++)
3873  {
3874  FreeElement(shared_edges[i]);
3875  }
3876 
3877  // The Mesh destructor is called automatically
3878 }
3879 
3880 }
3881 
3882 #endif
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition: intrules.hpp:228
int GetNFaceNeighbors() const
Definition: pmesh.hpp:119
void Create(ListOfIntegerSets &groups, int mpitag)
void SetState(int s)
Change the mesh state to NORMAL, TWO_LEVEL_COARSE, TWO_LEVEL_FINE.
Definition: mesh.cpp:7397
int Size() const
Logical size of the array.
Definition: array.hpp:109
Table * f_el_to_face
Definition: mesh.hpp:108
void Recreate(const int n, const int *p)
Definition: sets.cpp:59
int * GetJ()
Definition: table.hpp:108
const double * GetVertex(int i) const
Return pointer to vertex i&#39;s coordinates.
Definition: mesh.hpp:479
virtual ~ParMesh()
Definition: pmesh.cpp:3859
void SaveAsOne(std::ostream &out=std::cout)
Merge the local grid functions.
Definition: pgridfunc.cpp:321
void FreeElement(Element *E)
Definition: mesh.cpp:9779
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:4148
int f_NumOfEdges
Definition: mesh.hpp:64
void AddColumnsInRow(int r, int ncol)
Definition: table.hpp:72
int f_NumOfElements
Definition: mesh.hpp:62
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
Definition: table.cpp:74
virtual void GetVertices(Array< int > &v) const =0
Returns element&#39;s vertices.
Table * c_bel_to_edge
Definition: mesh.hpp:106
void GetFaceElements(int Face, int *Elem1, int *Elem2)
Definition: mesh.cpp:734
Array< Element * > boundary
Definition: mesh.hpp:70
int * GeneratePartitioning(int nparts, int part_method=1)
Definition: mesh.cpp:5068
virtual void ReorientTetMesh()
See the remarks for the serial version in mesh.hpp.
Definition: pmesh.cpp:1432
int own_nodes
Definition: mesh.hpp:119
int GetNBE() const
Returns number of boundary elements.
Definition: mesh.hpp:457
void GetLocalPtToSegTransformation(IsoparametricTransformation &, int)
Used in GetFaceElementTransformations (...)
Definition: mesh.cpp:424
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:161
Array< Element * > face_nbr_elements
Definition: pmesh.hpp:97
double Det() const
Calculates the determinant of the matrix (for 2x2 or 3x3 matrices)
Definition: densemat.cpp:416
int NumOfEdges
Definition: mesh.hpp:54
Lists all edges/faces in the nonconforming mesh.
Definition: ncmesh.hpp:124
int GetGroupSize(int g) const
int GetNSharedFaces() const
Return the number of shared faces (3D), edges (2D), vertices (1D)
Definition: pmesh.cpp:1409
void SetDims(int rows, int nnz)
Definition: table.cpp:132
int GetElementBaseGeometry(int i) const
Definition: mesh.hpp:494
const int * GetGroup(int g) const
void Copy(Array &copy) const
Create a copy of the current array.
Definition: array.hpp:160
T * GetData()
Returns the data.
Definition: array.hpp:91
int WantTwoLevelState
Definition: mesh.hpp:56
Data type dense matrix using column-major storage.
Definition: densemat.hpp:22
GridFunction * Nodes
Definition: mesh.hpp:118
int NumOfElements
Definition: mesh.hpp:53
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
Definition: table.cpp:179
IntegrationPointTransformation Loc2
Definition: eltrans.hpp:120
int GetBdrElementEdgeIndex(int i) const
Definition: mesh.cpp:4370
int GetNE() const
Returns number of elements.
Definition: mesh.hpp:454
const Element * GetFace(int i) const
Definition: mesh.hpp:490
virtual void SetVertices(const int *ind)
Set the indices the element according to the input.
Definition: element.cpp:17
void GetElementVertices(int i, Array< int > &dofs) const
Returns the indices of the dofs of element i.
Definition: mesh.hpp:501
virtual void OnMeshUpdated(Mesh *mesh)
Definition: pncmesh.cpp:127
Abstract parallel finite element space.
Definition: pfespace.hpp:28
bool have_face_nbr_data
Definition: pmesh.hpp:93
Array< int > face_nbr_vertices_offset
Definition: pmesh.hpp:96
void DeleteCoarseTables()
Definition: mesh.cpp:784
std::vector< MeshId > conforming
Definition: ncmesh.hpp:126
Array< int > face_nbr_group
Definition: pmesh.hpp:94
static int GetQuadOrientation(const int *base, const int *test)
Returns the orientation of &quot;test&quot; relative to &quot;base&quot;.
Definition: mesh.cpp:3924
void GetVertices(Vector &vert_coord) const
Definition: mesh.cpp:5773
Table * c_el_to_face
Definition: mesh.hpp:108
ElementTransformation * Elem2
Definition: eltrans.hpp:119
void CheckBdrElementOrientation(bool fix_it=true)
Check the orientation of the boundary elements.
Definition: mesh.cpp:3972
FaceElementTransformations * GetFaceElementTransformations(int FaceNo, int mask=31)
Definition: mesh.cpp:557
int Size_of_connections() const
Definition: table.hpp:92
Array< Element * > faces
Definition: mesh.hpp:71
const IntegrationRule * GetVertices(int GeomType)
Definition: geom.cpp:172
const NCList & GetSharedEdges()
Definition: pncmesh.hpp:90
void GetVertexToVertexTable(DSTable &) const
Definition: mesh.cpp:4487
void RedRefinement(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle)
Definition: mesh.hpp:185
int GetGeometryType() const
Definition: element.hpp:50
void DeleteAll()
Delete whole array.
Definition: array.hpp:455
void AddConnections(int r, const int *c, int nc)
Definition: table.cpp:96
Array< FaceInfo > fc_faces_info
Definition: mesh.hpp:109
bool IAmMaster(int g) const
A parallel extension of the NCMesh class.
Definition: pncmesh.hpp:66
Element * NewElement(int geom)
Definition: mesh.cpp:2152
Table * el_to_face
Definition: mesh.hpp:98
FaceElementTransformations FaceElemTr
Definition: mesh.hpp:113
ParNCMesh * pncmesh
Definition: pmesh.hpp:103
template void SortPairs< int, int >(Pair< int, int > *, int)
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition: mesh.cpp:3755
void ExchangeFaceNbrData()
Definition: pmesh.cpp:843
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
Definition: gridfunc.cpp:2138
void PrintAsOne(std::ostream &out=std::cout)
Definition: pmesh.cpp:2976
void GetElementJacobian(int i, DenseMatrix &J)
Definition: mesh.cpp:35
Geometry Geometries
Definition: geom.cpp:443
Array< int > face_nbr_elements_offset
Definition: pmesh.hpp:95
Symmetric 3D Table.
Definition: stable3d.hpp:28
static const int quad_orientations[8][4]
Definition: mesh.hpp:129
int Append(const T &el)
Append element to array, resize if necessary.
Definition: array.hpp:368
int State
Definition: mesh.hpp:56
Table * f_el_to_edge
Definition: mesh.hpp:106
int GetSharedFace(int sface) const
Return the local face index for the given shared face.
Definition: pmesh.cpp:1422
int GetNumNeighbors() const
void Clear()
Definition: table.cpp:340
void GetLocalSegToTriTransformation(IsoparametricTransformation &loc, int i)
Definition: mesh.cpp:438
std::vector< Master > masters
Definition: ncmesh.hpp:127
static FiniteElement * GetTransformationFEforElementType(int)
Definition: mesh.cpp:157
void AddConnection(int r, int c)
Definition: table.hpp:74
STable3D * GetElementToFaceTable(int ret_ftbl=0)
Definition: mesh.cpp:4841
static void Rotate3(int &, int &, int &)
Definition: mesh.hpp:899
int MeshGenerator()
Truegrid or NetGen?
Definition: mesh.hpp:447
Table send_face_nbr_vertices
Definition: pmesh.hpp:101
T Max() const
Definition: array.cpp:90
void InitTables()
Definition: mesh.cpp:758
int InitialPartition(int index) const
Assigns elements to processors at the initial stage (ParMesh creation).
Definition: pncmesh.hpp:222
void CheckElementOrientation(bool fix_it=true)
Check the orientation of the elements.
Definition: mesh.cpp:3770
int Insert(IntegerSet &s)
Definition: sets.cpp:82
Table * f_bel_to_edge
Definition: mesh.hpp:106
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
Definition: array.hpp:122
void Transpose(const Table &A, Table &At, int _ncols_A)
Transpose a Table.
Definition: table.cpp:385
int GetElementToEdgeTable(Table &, Array< int > &)
Definition: mesh.cpp:4512
int c_NumOfEdges
Definition: mesh.hpp:63
int GetElementType(int i) const
Returns the type of element i.
Definition: mesh.cpp:4382
Data type triangle element.
Definition: triangle.hpp:23
void MarkCoarseLevel()
Definition: ncmesh.cpp:2268
const Element * GetElement(int i) const
Definition: mesh.hpp:482
void GetLocalQuadToHexTransformation(IsoparametricTransformation &loc, int i)
Used in GetFaceElementTransformations (...)
Definition: mesh.cpp:536
static int State
Definition: element.hpp:100
IsoparametricTransformation Transformation2
Definition: mesh.hpp:111
void Init()
Definition: mesh.cpp:746
int f_NumOfVertices
Definition: mesh.hpp:62
int Size() const
Returns the number of TYPE I elements.
Definition: table.hpp:86
int GetVDim() const
Returns vector dimension.
Definition: fespace.hpp:154
FiniteElementSpace * FESpace()
Definition: gridfunc.hpp:270
virtual void ReorientTetMesh()
Definition: mesh.cpp:4914
int NumOfBdrElements
Definition: mesh.hpp:53
Table * el_to_edge
Definition: mesh.hpp:97
int c_NumOfBdrElements
Definition: mesh.hpp:61
Data type tetrahedron element.
Definition: tetrahedron.hpp:22
int GetOrdering() const
Return the ordering method.
Definition: fespace.hpp:176
int c_NumOfVertices
Definition: mesh.hpp:61
void GetBdrElementFace(int i, int *, int *) const
Return the index and the orientation of the face of bdr element i. (3D)
Definition: mesh.cpp:4319
virtual void Print(std::ostream &out=std::cout) const
Print the mesh to the given stream using the default MFEM mesh format.
Definition: mesh.cpp:8332
void Swap(Array< T > &, Array< T > &)
Definition: array.hpp:314
Array< int > bdr_attributes
Definition: mesh.hpp:140
void UseTwoLevelState(int use)
Definition: mesh.hpp:766
void RefineGroups(const DSTable &v_to_v, int *middle)
Update the groups after tet refinement.
Definition: pmesh.cpp:2204
Array< Vertex > face_nbr_vertices
Definition: pmesh.hpp:98
std::vector< Slave > slaves
Definition: ncmesh.hpp:128
Abstract finite element space.
Definition: fespace.hpp:62
static void PrintElement(const Element *, std::ostream &)
Definition: mesh.cpp:2213
int GetNeighborRank(int i) const
void AddAColumnInRow(int r)
Definition: table.hpp:71
void mfem_error(const char *msg)
Definition: error.cpp:23
void SetSize(int nsize)
Change logical size of the array, keep existing entries.
Definition: array.hpp:323
void SetSubVector(const Array< int > &dofs, const Vector &elemvect)
Definition: vector.cpp:493
Array< Vertex > vertices
Definition: mesh.hpp:69
MemAlloc< BisectedElement, 1024 > BEMemory
Definition: mesh.hpp:135
virtual void PrintInfo(std::ostream &out=std::cout)
Print various parallel mesh stats.
Definition: pmesh.cpp:3755
virtual void QuadUniformRefinement()
Refine quadrilateral mesh.
Definition: mesh.cpp:5919
virtual void HexUniformRefinement()
Refine hexahedral mesh.
Definition: mesh.cpp:6068
void Swap(Mesh &other, bool non_geometry=false)
Definition: mesh.cpp:6783
Array< Element * > elements
Definition: mesh.hpp:66
void ShiftUpI()
Definition: table.cpp:107
int meshgen
Definition: mesh.hpp:59
Table * bel_to_edge
Definition: mesh.hpp:101
virtual void PrintXG(std::ostream &out=std::cout) const
Definition: pmesh.cpp:2656
static FiniteElementCollection * New(const char *name)
Definition: fe_coll.cpp:44
Array< int > fc_be_to_edge
Definition: mesh.hpp:107
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element&#39;s vertices.
void GetLocalTriToTetTransformation(IsoparametricTransformation &loc, int i)
Used in GetFaceElementTransformations (...)
Definition: mesh.cpp:513
NURBSExtension * NURBSext
Definition: mesh.hpp:142
int GetNV() const
Definition: mesh.hpp:451
Array< int > be_to_edge
Definition: mesh.hpp:100
virtual const char * Name() const
Definition: fe_coll.hpp:36
Table * c_el_to_edge
Definition: mesh.hpp:106
virtual void Refine(const Array< Refinement > &refinements)
Definition: pncmesh.cpp:588
void GroupFace(int group, int i, int &face, int &o)
Definition: pmesh.cpp:700
int f_NumOfFaces
Definition: mesh.hpp:64
void GetLocalSegToQuadTransformation(IsoparametricTransformation &loc, int i)
Definition: mesh.cpp:461
int c_NumOfElements
Definition: mesh.hpp:61
void ExchangeFaceNbrNodes()
Definition: pmesh.cpp:1236
int c_NumOfFaces
Definition: mesh.hpp:63
A set of integers.
Definition: sets.hpp:23
void SetIJ(int *newI, int *newJ, int newsize=-1)
Definition: table.cpp:192
void MakeJ()
Definition: table.cpp:84
int GroupNFaces(int group)
Definition: pmesh.hpp:110
IsoparametricTransformation Transf
Definition: eltrans.hpp:110
double CalcSingularvalue(const int i) const
Return the i-th singular value (decreasing order) of NxN matrix, N=1,2,3.
Definition: densemat.cpp:1654
Array< FaceInfo > faces_info
Definition: mesh.hpp:94
virtual int GetNVertices() const =0
void SetAttribute(const int attr)
Set element&#39;s attribute.
Definition: element.hpp:83
STable3D * GetFacesTable()
Definition: mesh.cpp:4806
NCMesh * ncmesh
Definition: mesh.hpp:143
int Dim
Definition: mesh.hpp:50
int GetNEdges() const
Return the number of edges.
Definition: mesh.hpp:460
void GroupEdge(int group, int i, int &edge, int &o)
Definition: pmesh.cpp:692
int GetNFaces() const
Return the number of faces in a 3D mesh.
Definition: mesh.hpp:463
const NCList & GetSharedList(int type)
Helper to get shared vertices/edges/faces (&#39;type&#39; == 0/1/2 resp.).
Definition: pncmesh.hpp:105
double kappa
Definition: ex3.cpp:47
Vector data type.
Definition: vector.hpp:33
const FiniteElementCollection * FEColl() const
Definition: fespace.hpp:178
void GetNodes(Vector &node_coord) const
Definition: mesh.cpp:5844
void AverageVertices(int *indexes, int n, int result)
Definition: mesh.cpp:5892
int f_NumOfBdrElements
Definition: mesh.hpp:62
static int GetTriOrientation(const int *base, const int *test)
Returns the orientation of &quot;test&quot; relative to &quot;base&quot;.
Definition: mesh.cpp:3880
int * GetI()
Definition: table.hpp:107
void PrintAsOneXG(std::ostream &out=std::cout)
Old mesh format (Netgen/Truegrid) version of &#39;PrintAsOne&#39;.
Definition: pmesh.cpp:3232
void GenerateFaces()
Definition: mesh.cpp:4688
const NCList & GetSharedFaces()
Definition: pncmesh.hpp:98
int spaceDim
Definition: mesh.hpp:51
void ParseRefinementFlag(int refinement_edges[2], int &type, int &flag)
Definition: tetrahedron.cpp:22
int RowSize(int i) const
Definition: table.hpp:102
Class for parallel grid function.
Definition: pgridfunc.hpp:31
friend class ParNCMesh
Definition: mesh.hpp:45
Table send_face_nbr_elements
Definition: pmesh.hpp:100
List of integer sets.
Definition: sets.hpp:49
int NumOfVertices
Definition: mesh.hpp:53
Table * GetFaceToAllElementTable() const
Definition: pmesh.cpp:1303
Mesh * nc_coarse_level
Definition: mesh.hpp:123
void InitFromNCMesh(const NCMesh &ncmesh)
Initialize vertices/elements/boundary/tables from a nonconforming mesh.
Definition: mesh.cpp:6741
GroupTopology gtopo
Definition: pmesh.hpp:90
FaceElementTransformations * GetSharedFaceTransformations(int)
Definition: pmesh.cpp:1361
void Bisection(int i, const DSTable &, int *, int *, int *)
Definition: mesh.cpp:6991
int GetNGroups()
Definition: pmesh.hpp:105
Class for parallel meshes.
Definition: pmesh.hpp:28
Abstract data type element.
Definition: element.hpp:27
int GetAttribute(int i) const
Return the attribute of element i.
Definition: mesh.hpp:646
int GetFaceNbrRank(int fn) const
Definition: pmesh.cpp:1293
const Table & ElementToEdgeTable() const
Definition: mesh.cpp:4590
Data type line segment element.
Definition: segment.hpp:22
virtual void LimitNCLevel(int max_level)
To be implemented.
Definition: pncmesh.cpp:661
friend class Tetrahedron
Definition: mesh.hpp:132
Array< int > attributes
Definition: mesh.hpp:139
Table * GetVertexToElementTable()
The returned Table must be destroyed by the caller.
Definition: mesh.cpp:4212
const Element * GetBdrElement(int i) const
Definition: mesh.hpp:486
void UpdateNodes()
Update the nodes of a curved mesh after refinement.
Definition: mesh.cpp:5913
int GroupNEdges(int group)
Definition: pmesh.hpp:109
void GreenRefinement(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle)
Definition: mesh.hpp:191
static const int tri_orientations[6][3]
Definition: mesh.hpp:128
virtual void Print(std::ostream &out=std::cout) const
Definition: pmesh.cpp:2850
int NumOfFaces
Definition: mesh.hpp:54