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