MFEM  v3.4
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
pumi.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 "pumi.hpp"
13 
14 #ifdef MFEM_USE_PUMI
15 #ifdef MFEM_USE_MPI
16 
17 #include "mesh_headers.hpp"
18 #include "../fem/fem.hpp"
19 #include "../general/sort_pairs.hpp"
20 #include "../general/text.hpp"
21 #include "../general/sets.hpp"
22 
23 #include <iostream>
24 #include <sstream>
25 #include <fstream>
26 #include <limits>
27 #include <cmath>
28 #include <cstring>
29 #include <ctime>
30 
31 using namespace std;
32 
33 namespace mfem
34 {
35 
36 PumiMesh::PumiMesh(apf::Mesh2* apf_mesh, int generate_edges, int refine,
37  bool fix_orientation)
38 {
39  Load(apf_mesh, generate_edges, refine, fix_orientation);
40 }
41 
42 Element *PumiMesh::ReadElement(apf::MeshEntity* Ent, const int geom,
43  apf::Downward Verts,
44  const int Attr, apf::Numbering* vert_num)
45 {
46  Element *el;
47  int nv, *v;
48 
49  // Create element in MFEM
50  el = NewElement(geom);
51  nv = el->GetNVertices();
52  v = el->GetVertices();
53 
54  // Fill the connectivity
55  for (int i = 0; i < nv; ++i)
56  {
57  v[i] = apf::getNumber(vert_num, Verts[i], 0, 0);
58  }
59 
60  // Assign attribute
61  el->SetAttribute(Attr);
62 
63  return el;
64 }
65 
66 void PumiMesh::CountBoundaryEntity(apf::Mesh2* apf_mesh, const int BcDim,
67  int &NumBc)
68 {
69  apf::MeshEntity* ent;
70  apf::MeshIterator* itr = apf_mesh->begin(BcDim);
71 
72  while ((ent=apf_mesh->iterate(itr)))
73  {
74  apf::ModelEntity* mdEnt = apf_mesh->toModel(ent);
75  if (apf_mesh->getModelType(mdEnt) == BcDim)
76  {
77  NumBc++;
78  }
79  }
80  apf_mesh->end(itr);
81 
82  // Check if any boundary is detected
83  if (NumBc==0)
84  {
85  MFEM_ABORT("no boundary detected!");
86  }
87 }
88 
89 void PumiMesh::Load(apf::Mesh2* apf_mesh, int generate_edges, int refine,
90  bool fix_orientation)
91 {
92  int curved = 0, read_gf = 1;
93 
94  // Add a check on apf_mesh just in case
95  Clear();
96 
97  // First number vertices
98  apf::Field* apf_field_crd = apf_mesh->getCoordinateField();
99  apf::FieldShape* crd_shape = apf::getShape(apf_field_crd);
100  apf::Numbering* v_num_loc = apf::createNumbering(apf_mesh, "VertexNumbering",
101  crd_shape, 1);
102  // Check if it is a curved mesh
103  curved = (crd_shape->getOrder() > 1) ? 1 : 0;
104 
105  // Read mesh
106  ReadSCORECMesh(apf_mesh, v_num_loc, curved);
107  mfem::out << "After ReadSCORECMesh" << endl;
108  // at this point the following should be defined:
109  // 1) Dim
110  // 2) NumOfElements, elements
111  // 3) NumOfBdrElements, boundary
112  // 4) NumOfVertices, with allocated space in vertices
113  // 5) curved
114  // 5a) if curved == 0, vertices must be defined
115  // 5b) if curved != 0 and read_gf != 0,
116  // 'input' must point to a GridFunction
117  // 5c) if curved != 0 and read_gf == 0,
118  // vertices and Nodes must be defined
119 
120  // FinalizeTopology() will:
121  // - assume that generate_edges is true
122  // - assume that refine is false
123  // - does not check the orientation of regular and boundary elements
124  FinalizeTopology();
125 
126  if (curved && read_gf)
127  {
128  // Check it to be only Quadratic if higher order
129  Nodes = new GridFunctionPumi(this, apf_mesh, v_num_loc,
130  crd_shape->getOrder());
131  edge_vertex = NULL;
132  own_nodes = 1;
133  spaceDim = Nodes->VectorDim();
134 
135  // Set the 'vertices' from the 'Nodes'
136  for (int i = 0; i < spaceDim; i++)
137  {
138  Vector vert_val;
139  Nodes->GetNodalValues(vert_val, i+1);
140  for (int j = 0; j < NumOfVertices; j++)
141  {
142  vertices[j](i) = vert_val(j);
143  }
144  }
145  }
146 
147  // Delete numbering
148  apf::destroyNumbering(v_num_loc);
149 
150  Finalize(refine, fix_orientation);
151 }
152 
153 void PumiMesh::ReadSCORECMesh(apf::Mesh2* apf_mesh, apf::Numbering* v_num_loc,
154  const int curved)
155 {
156  // Here fill the element table from SCOREC MESH
157  // The vector of element pointers is generated with attr and connectivity
158 
159  apf::MeshIterator* itr = apf_mesh->begin(0);
160  apf::MeshEntity* ent;
161  NumOfVertices = 0;
162  while ((ent = apf_mesh->iterate(itr)))
163  {
164  // IDs start from 0
165  apf::number(v_num_loc, ent, 0, 0, NumOfVertices);
166  NumOfVertices++;
167  }
168  apf_mesh->end(itr);
169 
170  Dim = apf_mesh->getDimension();
171  NumOfElements = countOwned(apf_mesh,Dim);
172  elements.SetSize(NumOfElements);
173 
174  // Read elements from SCOREC Mesh
175  itr = apf_mesh->begin(Dim);
176  unsigned int j=0;
177  while ((ent = apf_mesh->iterate(itr)))
178  {
179  // Get vertices
180  apf::Downward verts;
181  apf_mesh->getDownward(ent,0,verts); // num_vert
182  // Get attribute Tag vs Geometry
183  int attr = 1;
184 
185  int geom_type = apf_mesh->getType(ent);
186  elements[j] = ReadElement(ent, geom_type, verts, attr, v_num_loc);
187  j++;
188  }
189  // End iterator
190  apf_mesh->end(itr);
191 
192  // Read Boundaries from SCOREC Mesh
193  // First we need to count them
194  int BCdim = Dim - 1;
195  NumOfBdrElements = 0;
196  CountBoundaryEntity(apf_mesh, BCdim, NumOfBdrElements);
197  boundary.SetSize(NumOfBdrElements);
198  j=0;
199 
200  // Read boundary from SCOREC mesh
201  itr = apf_mesh->begin(BCdim);
202  while ((ent = apf_mesh->iterate(itr)))
203  {
204  // Check if this mesh entity is on the model boundary
205  apf::ModelEntity* mdEnt = apf_mesh->toModel(ent);
206  if (apf_mesh->getModelType(mdEnt) == BCdim)
207  {
208  apf::Downward verts;
209  apf_mesh->getDownward(ent, 0, verts);
210  int attr = 1;
211  int geom_type = apf_mesh->getType(ent);
212  boundary[j] = ReadElement( ent, geom_type, verts, attr, v_num_loc);
213  j++;
214  }
215  }
216  apf_mesh->end(itr);
217 
218  // Fill vertices
219  vertices.SetSize(NumOfVertices);
220 
221  if (!curved)
222  {
223  apf::MeshIterator* itr = apf_mesh->begin(0);
224  spaceDim = Dim;
225 
226  while ((ent = apf_mesh->iterate(itr)))
227  {
228  unsigned int id = apf::getNumber(v_num_loc, ent, 0, 0);
229  apf::Vector3 Crds;
230  apf_mesh->getPoint(ent,0,Crds);
231 
232  for (int ii=0; ii<spaceDim; ii++)
233  {
234  vertices[id](ii) = Crds[ii];
235  }
236  }
237  apf_mesh->end(itr);
238  }
239 }
240 
241 // ParPumiMesh implementation
242 Element *ParPumiMesh::ReadElement(apf::MeshEntity* Ent, const int geom,
243  apf::Downward Verts,
244  const int Attr, apf::Numbering* vert_num)
245 {
246  Element *el;
247  int nv, *v;
248 
249  // Create element in MFEM
250  el = NewElement(geom);
251  nv = el->GetNVertices();
252  v = el->GetVertices();
253 
254  // Fill the connectivity
255  for (int i = 0; i < nv; ++i)
256  {
257  v[i] = apf::getNumber(vert_num, Verts[i], 0, 0);
258  }
259 
260  // Assign attribute
261  el->SetAttribute(Attr);
262 
263  return el;
264 }
265 
266 // This function loads a parallel PUMI mesh and returns the parallel MFEM mesh
267 // corresponding to it.
268 ParPumiMesh::ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh)
269 {
270  // Set the communicator for gtopo
271  gtopo.SetComm(comm);
272 
273  int i, j;
274  Array<int> vert;
275 
276  MyComm = comm;
277  MPI_Comm_size(MyComm, &NRanks);
278  MPI_Comm_rank(MyComm, &MyRank);
279 
280  Dim = apf_mesh->getDimension();
281  spaceDim = Dim;// mesh.spaceDim;
282 
283  // Iterator to get type
284  apf::MeshIterator* itr = apf_mesh->begin(Dim);
285  BaseGeom = apf_mesh->getType(apf_mesh->iterate(itr));
286  apf_mesh->end(itr);
287 
288  itr = apf_mesh->begin(Dim - 1);
289  BaseBdrGeom = apf_mesh->getType(apf_mesh->iterate(itr));
290  apf_mesh->end(itr);
291 
292  // Global numbering of vertices. This is necessary to build a local numbering
293  // that has the same ordering in each process.
294  apf::FieldShape* v_shape = apf::getConstant(0);
295  apf::Numbering* vLocNum =
296  apf::createNumbering(apf_mesh, "AuxVertexNumbering", v_shape, 1);
297  // Number
298  itr = apf_mesh->begin(0);
299  apf::MeshEntity* ent;
300  int owned_num = 0;
301  int all_num = 0;
302  int shared_num = 0;
303  while ((ent = apf_mesh->iterate(itr)))
304  {
305  all_num++;
306  if (apf_mesh->isOwned(ent))
307  {
308  apf::number(vLocNum, ent, 0, 0, owned_num++);
309  }
310  if (apf_mesh->isShared(ent))
311  {
312  shared_num++;
313  }
314  }
315  apf_mesh->end(itr);
316 
317  // Make the local numbering global
318  apf::GlobalNumbering* VertexNumbering = apf::makeGlobal(vLocNum, true);
319  apf::synchronize(VertexNumbering);
320 
321  // Take this process global IDs and sort
322  Array<int> thisIds(all_num);
323  Array<int> SharedVertIds(shared_num);
324  itr = apf_mesh->begin(0);
325  all_num = 0;
326  while ((ent = apf_mesh->iterate(itr)))
327  {
328  unsigned int id = apf::getNumber(VertexNumbering, ent, 0, 0);
329  thisIds[all_num++] = id;
330  }
331  apf_mesh->end(itr);
332  thisIds.Sort();
333 
334  // Create local numbering that respects the global ordering
335  apf::Field* apf_field_crd = apf_mesh->getCoordinateField();
336  apf::FieldShape* crd_shape = apf::getShape(apf_field_crd);
337  apf::Numbering* v_num_loc = apf::createNumbering(apf_mesh,
338  "LocalVertexNumbering",
339  crd_shape, 1);
340 
341  NumOfVertices = 0;
342  shared_num = 0;
343  itr = apf_mesh->begin(0);
344  while ((ent = apf_mesh->iterate(itr)))
345  {
346  // ID from global numbering
347  unsigned int id = apf::getNumber(VertexNumbering, ent, 0, 0);
348  // Find its position at sorted list
349  int ordered_id = thisIds.FindSorted(id);
350  // Assign as local number
351  apf::number(v_num_loc, ent, 0, 0, ordered_id);
352  NumOfVertices++;
353 
354  // Add to shared vertices list
355  if (apf_mesh->isShared(ent))
356  {
357  SharedVertIds[shared_num++] = ordered_id;
358  }
359  }
360  apf_mesh->end(itr);
361  SharedVertIds.Sort();
362  apf::destroyGlobalNumbering(VertexNumbering);
363 
364  vertices.SetSize(NumOfVertices);
365  // Set vertices
366  itr = apf_mesh->begin(0);
367  while ((ent = apf_mesh->iterate(itr)))
368  {
369  unsigned int id = apf::getNumber(v_num_loc, ent, 0, 0);
370  apf::Vector3 Crds;
371  apf_mesh->getPoint(ent,0,Crds);
372 
373  for (int ii=0; ii<spaceDim; ii++)
374  {
375  vertices[id](ii) = Crds[ii]; // Assuming the IDs are ordered and from 0
376  }
377  }
378  apf_mesh->end(itr);
379 
380  // Fill the elements
381  NumOfElements = countOwned(apf_mesh,Dim);
382  elements.SetSize(NumOfElements);
383 
384  // Read elements from SCOREC Mesh
385  itr = apf_mesh->begin(Dim);
386  j=0;
387  while ((ent = apf_mesh->iterate(itr)))
388  {
389  // Get vertices
390  apf::Downward verts;
391  apf_mesh->getDownward(ent,0,verts);
392 
393  // Get attribute Tag vs Geometry
394  int attr = 1;
395  int geom_type = BaseGeom;
396  elements[j] = ReadElement(ent, geom_type, verts, attr, v_num_loc);
397  j++;
398  }
399  // End iterator
400  apf_mesh->end(itr);
401 
402  Table *edge_element = NULL;
403 
404  // Count number of boundaries by classification
405  int BcDim = Dim - 1;
406  itr = apf_mesh->begin(BcDim);
407  NumOfBdrElements = 0;
408 
409  while ((ent=apf_mesh->iterate(itr)))
410  {
411  apf::ModelEntity* mdEnt = apf_mesh->toModel(ent);
412  if (apf_mesh->getModelType(mdEnt) == BcDim)
413  {
414  NumOfBdrElements++;
415  }
416  }
417  apf_mesh->end(itr);
418 
419  boundary.SetSize(NumOfBdrElements);
420  int bdr_ctr=0;
421  // Read boundary from SCOREC mesh
422  itr = apf_mesh->begin(BcDim);
423  while ((ent = apf_mesh->iterate(itr)))
424  {
425  // Check if this mesh entity is on the model boundary
426  apf::ModelEntity* mdEnt = apf_mesh->toModel(ent);
427  if (apf_mesh->getModelType(mdEnt) == BcDim)
428  {
429  apf::Downward verts;
430  apf_mesh->getDownward(ent, 0, verts);
431  int attr = 1 ;
432  int geom_type = BaseBdrGeom;// apf_mesh->getType(ent);
433  boundary[bdr_ctr] = ReadElement(ent, geom_type, verts, attr,
434  v_num_loc);
435  bdr_ctr++;
436  }
437  }
438  apf_mesh->end(itr);
439 
440  // The next two methods are called by FinalizeTopology() called below:
441  // Mesh::SetMeshGen();
442  // Mesh::SetAttributes();
443 
444  // This is called by the default Mesh constructor
445  // Mesh::InitTables();
446 
447  this->FinalizeTopology();
448 
449  STable3D *faces_tbl = (Dim == 3) ? GetFacesTable() : NULL;
450 
451  ListOfIntegerSets groups;
452  IntegerSet group;
453 
454  // The first group is the local one
455  group.Recreate(1, &MyRank);
456  groups.Insert(group);
457 
458  MFEM_ASSERT(Dim >= 3 || GetNFaces() == 0,
459  "[proc " << MyRank << "]: invalid state");
460 
461  // Determine shared faces
462  int sface_counter = 0;
463  Array<int> face_group(GetNFaces());
464  apf::FieldShape* fc_shape =apf::getConstant(2);
465  apf::Numbering* faceNum = apf::createNumbering(apf_mesh, "FaceNumbering",
466  fc_shape, 1);
467  Array<int> SharedFaceIds;
468  if (Dim > 2)
469  {
470  // Number Faces
471  apf::Numbering* AuxFaceNum =
472  apf::numberOwnedDimension(apf_mesh, "AuxFaceNumbering", 2);
473  apf::GlobalNumbering* GlobalFaceNum = apf::makeGlobal(AuxFaceNum, true);
474  apf::synchronize(GlobalFaceNum);
475 
476  // Take this process global IDs and sort
477  Array<int> thisFaceIds(GetNFaces());
478 
479  itr = apf_mesh->begin(2);
480  all_num = 0;
481  shared_num = 0;
482  while ((ent = apf_mesh->iterate(itr)))
483  {
484  unsigned int id = apf::getNumber(GlobalFaceNum, ent, 0, 0);
485  thisFaceIds[all_num++] = id;
486  if (apf_mesh->isShared(ent))
487  {
488  shared_num++;
489  }
490  }
491  apf_mesh->end(itr);
492  thisFaceIds.Sort();
493 
494  // Create local numbering that respects the global ordering
495  SharedFaceIds.SetSize(shared_num);
496  shared_num = 0;
497  itr = apf_mesh->begin(2);
498  while ((ent = apf_mesh->iterate(itr)))
499  {
500  // ID from global numbering
501  unsigned int id = apf::getNumber(GlobalFaceNum, ent, 0, 0);
502  // Find its position at sorted list
503  int ordered_id = thisFaceIds.FindSorted(id);
504  // Assign as local number
505  apf::number(faceNum, ent, 0, 0, ordered_id);
506 
507  if (apf_mesh->isShared(ent))
508  {
509  SharedFaceIds[shared_num++] = ordered_id;
510  }
511  }
512  apf_mesh->end(itr);
513  SharedFaceIds.Sort();
514  apf::destroyGlobalNumbering(GlobalFaceNum);
515 
516  itr = apf_mesh->begin(2);
517  while ((ent = apf_mesh->iterate(itr)))
518  {
519  int faceId = apf::getNumber(faceNum, ent, 0, 0);
520  face_group[faceId] = -1;
521  if (apf_mesh->isShared(ent))
522  {
523  // Number of adjacent element
524  const int thisNumAdjs = 2;
525  int eleRanks[thisNumAdjs];
526 
527  // Get the IDs
528  apf::Parts res;
529  apf_mesh->getResidence(ent, res);
530  int kk = 0;
531  for (std::set<int>::iterator itr = res.begin();
532  itr != res.end(); ++itr)
533  {
534  eleRanks[kk++] = *itr;
535  }
536 
537  group.Recreate(2, eleRanks);
538  face_group[faceId] = groups.Insert(group) - 1;
539  sface_counter++;
540  }
541  }
542  apf_mesh->end(itr);
543  }
544 
545  // Determine shared edges
546  int sedge_counter = 0;
547  if (!edge_element)
548  {
549  edge_element = new Table;
550  if (Dim == 1)
551  {
552  edge_element->SetDims(0,0);
553  }
554  else
555  {
556  edge_element->SetSize(GetNEdges(), 1);
557  }
558  }
559 
560  // Number Edges
561  apf::Numbering* AuxEdgeNum = apf::numberOwnedDimension(apf_mesh,
562  "EdgeNumbering", 1);
563  apf::GlobalNumbering* GlobalEdgeNum = apf::makeGlobal(AuxEdgeNum, true);
564  apf::synchronize(GlobalEdgeNum);
565 
566  // Take this process global IDs and sort
567  Array<int> thisEdgeIds(GetNEdges());
568 
569  itr = apf_mesh->begin(1);
570  all_num = 0;
571  shared_num = 0;
572  while ((ent = apf_mesh->iterate(itr)))
573  {
574  unsigned int id = apf::getNumber(GlobalEdgeNum, ent, 0, 0);
575  thisEdgeIds[all_num++] = id;
576  if (apf_mesh->isShared(ent))
577  {
578  shared_num++;
579  }
580  }
581  apf_mesh->end(itr);
582  thisEdgeIds.Sort();
583 
584  // Create local numbering that respects the global ordering
585  apf::FieldShape* ed_shape =apf::getConstant(1);
586  apf::Numbering* edgeNum = apf::createNumbering(apf_mesh, "EdgeNumbering",
587  ed_shape, 1);
588 
589  Array<int> SharedEdgeIds(shared_num);
590  shared_num = 0;
591  itr = apf_mesh->begin(1);
592  while ((ent = apf_mesh->iterate(itr)))
593  {
594  // ID from global numbering
595  unsigned int id = apf::getNumber(GlobalEdgeNum, ent, 0, 0);
596  // Find its position at sorted list
597  int ordered_id = thisEdgeIds.FindSorted(id);
598  // Assign as local number
599  apf::number(edgeNum, ent, 0, 0, ordered_id);
600 
601  if (apf_mesh->isShared(ent))
602  {
603  SharedEdgeIds[shared_num++] = ordered_id;
604  }
605  }
606  apf_mesh->end(itr);
607  SharedEdgeIds.Sort();
608  apf::destroyGlobalNumbering(GlobalEdgeNum);
609 
610  itr = apf_mesh->begin(1);
611  i = 0;
612  while ((ent = apf_mesh->iterate(itr)))
613  {
614  int edId = apf::getNumber(edgeNum, ent, 0, 0);
615  edge_element->GetRow(edId)[0] = -1;
616 
617  if (apf_mesh->isShared(ent))
618  {
619  sedge_counter++;
620 
621  // Number of adjacent element
622  apf::Parts res;
623  apf_mesh->getResidence(ent, res);
624  int thisNumAdjs = res.size();
625  Array<int> eleRanks(thisNumAdjs);
626 
627  // Get the IDs
628  int kk = 0;
629  for (std::set<int>::iterator itr = res.begin();
630  itr != res.end(); itr++)
631  {
632  eleRanks[kk++] = *itr;
633  }
634 
635  // Generate the group
636  group.Recreate(thisNumAdjs, eleRanks);
637  edge_element->GetRow(edId)[0] = groups.Insert(group) - 1;
638 
639  }
640  i++;
641  }
642  apf_mesh->end(itr);
643 
644  // Determine shared vertices
645  int svert_counter = 0;
646  Table *vert_element = new Table;
647  vert_element->SetSize(GetNV(), 1);
648 
649  itr = apf_mesh->begin(0);
650  while ((ent = apf_mesh->iterate(itr)))
651  {
652  int vtId = apf::getNumber(v_num_loc, ent, 0, 0);
653  vert_element->GetRow(vtId)[0] = -1;
654 
655  if (apf_mesh->isShared(ent))
656  {
657  svert_counter++;
658  // Number of adjacent element
659  apf::Parts res;
660  apf_mesh->getResidence(ent, res);
661  int thisNumAdjs = res.size();
662  Array<int> eleRanks(thisNumAdjs);
663 
664  // Get the IDs
665  int kk = 0;
666  for (std::set<int>::iterator itr = res.begin();
667  itr != res.end(); itr++)
668  {
669  eleRanks[kk++] = *itr;
670  }
671 
672  group.Recreate(thisNumAdjs, eleRanks);
673  vert_element->GetRow(vtId)[0]= groups.Insert(group) - 1;
674  }
675  }
676  apf_mesh->end(itr);
677 
678  // Build group_sface
679  group_sface.MakeI(groups.Size()-1);
680 
681  for (i = 0; i < face_group.Size(); i++)
682  {
683  if (face_group[i] >= 0)
684  {
685  group_sface.AddAColumnInRow(face_group[i]);
686  }
687  }
688 
689  group_sface.MakeJ();
690 
691  sface_counter = 0;
692  for (i = 0; i < face_group.Size(); i++)
693  {
694  if (face_group[i] >= 0)
695  {
696  group_sface.AddConnection(face_group[i], sface_counter++);
697  }
698  }
699 
700  group_sface.ShiftUpI();
701 
702  // Build group_sedge
703  group_sedge.MakeI(groups.Size()-1);
704 
705  for (i = 0; i < edge_element->Size(); i++)
706  {
707  if (edge_element->GetRow(i)[0] >= 0)
708  {
709  group_sedge.AddAColumnInRow(edge_element->GetRow(i)[0]);
710  }
711  }
712 
713  group_sedge.MakeJ();
714 
715  sedge_counter = 0;
716  for (i = 0; i < edge_element->Size(); i++)
717  {
718  if (edge_element->GetRow(i)[0] >= 0)
719  {
720  group_sedge.AddConnection(edge_element->GetRow(i)[0], sedge_counter++);
721  }
722  }
723 
724  group_sedge.ShiftUpI();
725 
726  // Build group_svert
727  group_svert.MakeI(groups.Size()-1);
728 
729  for (i = 0; i < vert_element->Size(); i++)
730  {
731  if (vert_element->GetRow(i)[0] >= 0)
732  {
733  group_svert.AddAColumnInRow(vert_element->GetRow(i)[0]);
734  }
735  }
736 
737  group_svert.MakeJ();
738 
739  svert_counter = 0;
740  for (i = 0; i < vert_element->Size(); i++)
741  {
742  if (vert_element->GetRow(i)[0] >= 0)
743  {
744  group_svert.AddConnection(vert_element->GetRow(i)[0], svert_counter++);
745  }
746  }
747  group_svert.ShiftUpI();
748 
749  // Build shared_faces and sface_lface
750  shared_faces.SetSize(sface_counter);
751  sface_lface. SetSize(sface_counter);
752 
753  if (Dim == 3)
754  {
755  sface_counter = 0;
756  itr = apf_mesh->begin(2);
757  while ((ent = apf_mesh->iterate(itr)))
758  {
759  if (apf_mesh->isShared(ent))
760  {
761  // Generate the face
762  int fcId = apf::getNumber(faceNum, ent, 0, 0);
763  int ctr = SharedFaceIds.FindSorted(fcId);
764 
765  apf::Downward verts;
766  apf_mesh->getDownward(ent,0,verts);
767  int geom = BaseBdrGeom;
768  int attr = 1;
769  shared_faces[ctr] = ReadElement(ent, geom, verts, attr,
770  v_num_loc);
771 
772  int *v = shared_faces[ctr]->GetVertices();
773  switch ( geom )
774  {
775  case Element::TRIANGLE:
776  sface_lface[ctr] = (*faces_tbl)(v[0], v[1], v[2]);
777  // The marking for refinement is omitted. All done in PUMI
778  break;
779  case Element::QUADRILATERAL:
780  sface_lface[ctr] =
781  (*faces_tbl)(v[0], v[1], v[2], v[3]);
782  break;
783  }
784  sface_counter++;
785  }
786  }
787  apf_mesh->end(itr);
788  delete faces_tbl;
789  }
790 
791  // Build shared_edges and sedge_ledge
792  shared_edges.SetSize(sedge_counter);
793  sedge_ledge. SetSize(sedge_counter);
794 
795  {
796  DSTable v_to_v(NumOfVertices);
797  GetVertexToVertexTable(v_to_v);
798 
799  sedge_counter = 0;
800  itr = apf_mesh->begin(1);
801  while ((ent = apf_mesh->iterate(itr)))
802  {
803  if (apf_mesh->isShared(ent))
804  {
805  int edId = apf::getNumber(edgeNum, ent, 0, 0);
806  int ctr = SharedEdgeIds.FindSorted(edId);
807  apf::Downward verts;
808  apf_mesh->getDownward(ent, 0, verts);
809  int id1, id2;
810  id1 = apf::getNumber(v_num_loc, verts[0], 0, 0);
811  id2 = apf::getNumber(v_num_loc, verts[1], 0, 0);
812  if (id1 > id2) { swap(id1,id2); }
813 
814  shared_edges[ctr] = new Segment(id1, id2, 1);
815  if ((sedge_ledge[ctr] = v_to_v(id1,id2)) < 0)
816  {
817  mfem::err << "\n\n\n" << MyRank << ": ParPumiMesh::ParPumiMesh: "
818  << "ERROR in v_to_v\n\n" << endl;
819  mfem_error();
820  }
821 
822  sedge_counter++;
823  }
824  }
825  }
826  apf_mesh->end(itr);
827 
828  delete edge_element;
829 
830  // Build svert_lvert
831  svert_lvert.SetSize(svert_counter);
832 
833  svert_counter = 0;
834  itr = apf_mesh->begin(0);
835  while ((ent = apf_mesh->iterate(itr)))
836  {
837  if (apf_mesh->isShared(ent))
838  {
839  int vt_id = apf::getNumber(v_num_loc, ent, 0, 0);
840  int ctr = SharedVertIds.FindSorted(vt_id);
841  svert_lvert[ctr] = vt_id;
842  svert_counter++;
843  }
844  }
845  apf_mesh->end(itr);
846 
847  delete vert_element;
848 
849  // Build the group communication topology
850  gtopo.Create(groups, 822);
851 
852  // Set nodes for higher order mesh
853  int curved = (crd_shape->getOrder() > 1) ? 1 : 0;
854  if (curved) // curved mesh
855  {
856  GridFunctionPumi auxNodes(this, apf_mesh, v_num_loc,
857  crd_shape->getOrder());
858  Nodes = new ParGridFunction(this, &auxNodes);
859  Nodes->Vector::Swap(auxNodes);
860  this->edge_vertex = NULL;
861  own_nodes = 1;
862  }
863  apf::destroyNumbering(edgeNum);
864  apf::destroyNumbering(faceNum);
865 }
866 
867 
868 // GridFunctionPumi Implementation needed for high order meshes
869 GridFunctionPumi::GridFunctionPumi(Mesh* m, apf::Mesh2* PumiM,
870  apf::Numbering* v_num_loc,
871  const int mesh_order)
872 {
873  int spDim = m->SpaceDimension();
874  // Note: default BasisType for 'fec' is GaussLobatto.
875  fec = new H1_FECollection(mesh_order, m->Dimension());
876  int ordering = Ordering::byVDIM; // x1y1z1/x2y2z2/...
877  fes = new FiniteElementSpace(m, fec, spDim, ordering);
878  int data_size = fes->GetVSize();
879 
880  // Read PUMI mesh data
881  this->SetSize(data_size);
882  double* PumiData = this->GetData();
883 
884  apf::MeshEntity* ent;
885  apf::MeshIterator* itr;
886 
887  // Assume all element type are the same i.e. tetrahedral
888  const FiniteElement* H1_elem = fes->GetFE(0);
889  const IntegrationRule &All_nodes = H1_elem->GetNodes();
890  int nnodes = All_nodes.Size();
891 
892  // Loop over elements
893  apf::Field* crd_field = PumiM->getCoordinateField();
894 
895  int nc = apf::countComponents(crd_field);
896  int iel = 0;
897  itr = PumiM->begin(m->Dimension());
898  while ((ent = PumiM->iterate(itr)))
899  {
900  Array<int> vdofs;
901  fes->GetElementVDofs(iel, vdofs);
902 
903  // Create PUMI element to interpolate
904  apf::MeshElement* mE = apf::createMeshElement(PumiM, ent);
905  apf::Element* elem = apf::createElement(crd_field, mE);
906 
907  // Vertices are already interpolated
908  for (int ip = 0; ip < nnodes; ip++)
909  {
910  // Take parametric coordinates of the node
911  apf::Vector3 param;
912  param[0] = All_nodes.IntPoint(ip).x;
913  param[1] = All_nodes.IntPoint(ip).y;
914  param[2] = All_nodes.IntPoint(ip).z;
915 
916  // Compute the interpolating coordinates
917  apf::DynamicVector phCrd(nc);
918  apf::getComponents(elem, param, &phCrd[0]);
919 
920  // Fill the nodes list
921  for (int kk = 0; kk < spDim; ++kk)
922  {
923  int dof_ctr = ip + kk * nnodes;
924  PumiData[vdofs[dof_ctr]] = phCrd[kk];
925  }
926  }
927  iel++;
928  apf::destroyElement(elem);
929  apf::destroyMeshElement(mE);
930  }
931  PumiM->end(itr);
932 
933  sequence = 0;
934 }
935 
936 // Copy the adapted mesh to the original mesh and increase the sequence to be
937 // able to Call Update() methods of FESpace, Linear and Bilinear forms.
938 void ParPumiMesh::UpdateMesh(const ParMesh* AdaptedpMesh)
939 {
940  // Destroy the ParMesh data fields.
941  delete pncmesh;
942  pncmesh = NULL;
943 
944  DeleteFaceNbrData();
945 
946  for (int i = 0; i < shared_faces.Size(); i++)
947  {
948  FreeElement(shared_faces[i]);
949  }
950  for (int i = 0; i < shared_edges.Size(); i++)
951  {
952  FreeElement(shared_edges[i]);
953  }
954  shared_faces.DeleteAll();
955  shared_edges.DeleteAll();
956  group_svert.Clear();
957  group_sedge.Clear();
958  group_sface.Clear();
959  svert_lvert.DeleteAll();
960  sedge_ledge.DeleteAll();
961  sface_lface.DeleteAll();
962 
963  // Destroy the Mesh data fields.
964  Destroy();
965 
966  // Assuming Dim, spaceDim, geom type is unchanged
967  MFEM_ASSERT(Dim == AdaptedpMesh->Dim, "");
968  MFEM_ASSERT(spaceDim == AdaptedpMesh->spaceDim, "");
969  MFEM_ASSERT(BaseGeom == AdaptedpMesh->BaseGeom, "");
970  MFEM_ASSERT(BaseBdrGeom == AdaptedpMesh->BaseBdrGeom, "");
971 
972  NumOfVertices = AdaptedpMesh->GetNV();
973  NumOfElements = AdaptedpMesh->GetNE();
974  NumOfBdrElements = AdaptedpMesh->GetNBE();
975  NumOfEdges = AdaptedpMesh->GetNEdges();
976  NumOfFaces = AdaptedpMesh->GetNFaces();
977 
978  meshgen = AdaptedpMesh->meshgen;
979 
980  // Sequence is increased by one to trigger update in FEspace etc.
981  sequence++;
982  last_operation = Mesh::NONE;
983 
984  // Duplicate the elements
985  elements.SetSize(NumOfElements);
986  for (int i = 0; i < NumOfElements; i++)
987  {
988  elements[i] = AdaptedpMesh->GetElement(i)->Duplicate(this);
989  }
990 
991  // Copy the vertices
992  AdaptedpMesh->vertices.Copy(vertices);
993 
994  // Duplicate the boundary
995  boundary.SetSize(NumOfBdrElements);
996  for (int i = 0; i < NumOfBdrElements; i++)
997  {
998  boundary[i] = AdaptedpMesh->GetBdrElement(i)->Duplicate(this);
999  }
1000 
1001  // Copy the element-to-face Table, el_to_face
1002  el_to_face = (AdaptedpMesh->el_to_face) ?
1003  new Table(*(AdaptedpMesh->el_to_face)) : NULL;
1004 
1005  // Copy the boundary-to-face Array, be_to_face.
1006  AdaptedpMesh->be_to_face.Copy(be_to_face);
1007 
1008  // Copy the element-to-edge Table, el_to_edge
1009  el_to_edge = (AdaptedpMesh->el_to_edge) ?
1010  new Table(*(AdaptedpMesh->el_to_edge)) : NULL;
1011 
1012  // Copy the boudary-to-edge Table, bel_to_edge (3D)
1013  bel_to_edge = (AdaptedpMesh->bel_to_edge) ?
1014  new Table(*(AdaptedpMesh->bel_to_edge)) : NULL;
1015 
1016  // Copy the boudary-to-edge Array, be_to_edge (2D)
1017  AdaptedpMesh->be_to_edge.Copy(be_to_edge);
1018 
1019  // Duplicate the faces and faces_info.
1020  faces.SetSize(AdaptedpMesh->faces.Size());
1021  for (int i = 0; i < faces.Size(); i++)
1022  {
1023  Element *face = AdaptedpMesh->faces[i]; // in 1D the faces are NULL
1024  faces[i] = (face) ? face->Duplicate(this) : NULL;
1025  }
1026  AdaptedpMesh->faces_info.Copy(faces_info);
1027 
1028  // Do NOT copy the element-to-element Table, el_to_el
1029  el_to_el = NULL;
1030 
1031  // Do NOT copy the face-to-edge Table, face_edge
1032  face_edge = NULL;
1033 
1034  // Copy the edge-to-vertex Table, edge_vertex
1035  edge_vertex = (AdaptedpMesh->edge_vertex) ?
1036  new Table(*(AdaptedpMesh->edge_vertex)) : NULL;
1037 
1038  // Copy the attributes and bdr_attributes
1039  AdaptedpMesh->attributes.Copy(attributes);
1040  AdaptedpMesh->bdr_attributes.Copy(bdr_attributes);
1041 
1042  // PUMI meshes cannot use NURBS meshes.
1043  MFEM_VERIFY(AdaptedpMesh->NURBSext == NULL,
1044  "invalid adapted mesh: it is a NURBS mesh");
1045  NURBSext = NULL;
1046 
1047  // PUMI meshes cannot use NCMesh/ParNCMesh.
1048  MFEM_VERIFY(AdaptedpMesh->ncmesh == NULL && AdaptedpMesh->pncmesh == NULL,
1049  "invalid adapted mesh: it is a non-conforming mesh");
1050  ncmesh = NULL;
1051  pncmesh = NULL;
1052 
1053  // Parallel Implications
1054  AdaptedpMesh->group_svert.Copy(group_svert);
1055  AdaptedpMesh->group_sedge.Copy(group_sedge);
1056  AdaptedpMesh->group_sface.Copy(group_sface);
1057  AdaptedpMesh->gtopo.Copy(gtopo);
1058 
1059  MyComm = AdaptedpMesh->MyComm;
1060  NRanks = AdaptedpMesh->NRanks;
1061  MyRank = AdaptedpMesh->MyRank;
1062 
1063  // Duplicate the shared_edges
1064  shared_edges.SetSize(AdaptedpMesh->shared_edges.Size());
1065  for (int i = 0; i < shared_edges.Size(); i++)
1066  {
1067  shared_edges[i] = AdaptedpMesh->shared_edges[i]->Duplicate(this);
1068  }
1069 
1070  // Duplicate the shared_faces
1071  shared_faces.SetSize(AdaptedpMesh->shared_faces.Size());
1072  for (int i = 0; i < shared_faces.Size(); i++)
1073  {
1074  shared_faces[i] = AdaptedpMesh->shared_faces[i]->Duplicate(this);
1075  }
1076 
1077  // Copy the shared-to-local index Arrays
1078  AdaptedpMesh->svert_lvert.Copy(svert_lvert);
1079  AdaptedpMesh->sedge_ledge.Copy(sedge_ledge);
1080  AdaptedpMesh->sface_lface.Copy(sface_lface);
1081 
1082  // Do not copy face-neighbor data (can be generated if needed)
1083  have_face_nbr_data = false;
1084 
1085  // Copy the Nodes as a ParGridFunction, including the FiniteElementCollection
1086  // and the FiniteElementSpace (as a ParFiniteElementSpace)
1087  if (AdaptedpMesh->Nodes)
1088  {
1089  FiniteElementSpace *fes = AdaptedpMesh->Nodes->FESpace();
1090  const FiniteElementCollection *fec = fes->FEColl();
1091  FiniteElementCollection *fec_copy =
1092  FiniteElementCollection::New(fec->Name());
1093  ParFiniteElementSpace *pfes_copy =
1094  new ParFiniteElementSpace(this, fec_copy, fes->GetVDim(),
1095  fes->GetOrdering());
1096  Nodes = new ParGridFunction(pfes_copy);
1097  Nodes->MakeOwner(fec_copy);
1098  *Nodes = *(AdaptedpMesh->Nodes);
1099  own_nodes = 1;
1100  }
1101 }
1102 
1103 // Transfer a mixed vector-scalar field (i.e. velocity,pressure) and the
1104 // magnitude of the vector field to use for mesh adaptation.
1105 void ParPumiMesh::FieldMFEMtoPUMI(apf::Mesh2* apf_mesh,
1106  ParGridFunction* grid_vel,
1107  ParGridFunction* grid_pr,
1108  apf::Field* VelField,
1109  apf::Field* PrField,
1110  apf::Field* VelMagField)
1111 {
1112  apf::FieldShape* VelFieldShape = getShape(VelField);
1113  int num_nodes = 4 * VelFieldShape->countNodesOn(0) + // Vertex
1114  6 * VelFieldShape->countNodesOn(1) + // Edge
1115  4 * VelFieldShape->countNodesOn(2) + // Triangle
1116  VelFieldShape->countNodesOn(4); // Tetrahedron
1117 
1118  // Define integration points
1119  IntegrationRule pumi_nodes(num_nodes);
1120  int ip_cnt = 0;
1121  apf::Vector3 xi_crd(0.,0.,0.);
1122 
1123  // Create a template of dof holders coordinates in parametric coordinates.
1124  // The ordering is taken care of when the field is transferred to PUMI.
1125 
1126  // Dofs on Vertices
1127  IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++);
1128  double pt_crd[3] = {0., 0., 0.};
1129  ip.Set(pt_crd, 3);
1130  for (int kk = 0; kk < 3; kk++)
1131  {
1132  IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++);
1133  double pt_crd[3] = {0.,0.,0.};
1134  pt_crd[kk] = 1.0;
1135  ip.Set(pt_crd, 3);
1136  }
1137  // Dofs on Edges
1138  if (VelFieldShape->hasNodesIn(apf::Mesh::EDGE))
1139  {
1140  const int nn = VelFieldShape->countNodesOn(apf::Mesh::EDGE);
1141  for (int ii = 0; ii < 6; ii++)
1142  {
1143  for (int jj = 0; jj < nn; jj++)
1144  {
1145  VelFieldShape->getNodeXi(apf::Mesh::EDGE, jj, xi_crd);
1146  xi_crd[0] = 0.5 * (xi_crd[0] + 1.);// from (-1,1) to (0,1)
1147  double pt_crd[3] = {0., 0., 0.};
1148  switch (ii)
1149  {
1150  case 0:
1151  pt_crd[0] = xi_crd[0];
1152  break;
1153  case 1:
1154  pt_crd[0] = 1. - xi_crd[0];
1155  pt_crd[1] = xi_crd[0];
1156  break;
1157  case 2:
1158  pt_crd[1] = xi_crd[0];
1159  break;
1160  case 3:
1161  pt_crd[2] = xi_crd[0];
1162  break;
1163  case 4:
1164  pt_crd[0] = 1. - xi_crd[0];
1165  pt_crd[2] = xi_crd[0];
1166  break;
1167  case 5:
1168  pt_crd[1] = 1. - xi_crd[0];
1169  pt_crd[2] = xi_crd[0];
1170  break;
1171  }
1172  IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++);
1173  ip.Set(pt_crd, 3);
1174  }
1175  }
1176  }
1177  // Dofs on Faces
1178  if (VelFieldShape->hasNodesIn(apf::Mesh::TRIANGLE))
1179  {
1180  const int nn = VelFieldShape->countNodesOn(apf::Mesh::TRIANGLE);
1181  for (int ii = 0; ii < 4; ii++)
1182  {
1183  for (int jj = 0; jj < nn; jj++)
1184  {
1185  VelFieldShape->getNodeXi(apf::Mesh::TRIANGLE, jj, xi_crd);
1186  double pt_crd[3] = {0., 0., 0.};
1187  switch (ii)
1188  {
1189  case 0:
1190  pt_crd[0] = xi_crd[0];
1191  pt_crd[1] = xi_crd[1];
1192  break;
1193  case 1:
1194  pt_crd[0] = xi_crd[0];
1195  pt_crd[2] = xi_crd[2];
1196  break;
1197  case 2:
1198  pt_crd[0] = xi_crd[0];
1199  pt_crd[1] = xi_crd[1];
1200  pt_crd[2] = xi_crd[2];
1201  break;
1202  case 3:
1203  pt_crd[1] = xi_crd[0];
1204  pt_crd[2] = xi_crd[1];
1205  break;
1206  }
1207  IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++);
1208  ip.Set(pt_crd, 3);
1209  }
1210  }
1211  }
1212  MFEM_ASSERT(ip_cnt == num_nodes, "");
1213 
1214  // Other dofs
1215  apf::MeshEntity* ent;
1216  apf::MeshIterator* itr = apf_mesh->begin(3);
1217  int iel = 0;
1218  while ((ent = apf_mesh->iterate(itr)))
1219  {
1220  // Get the solution
1221  Vector u_vel, v_vel, w_vel;
1222  grid_vel->GetValues(iel, pumi_nodes, u_vel, 1);
1223  grid_vel->GetValues(iel, pumi_nodes, v_vel, 2);
1224  grid_vel->GetValues(iel, pumi_nodes, w_vel, 3);
1225 
1226  Vector pr;
1227  grid_pr->GetValues(iel, pumi_nodes, pr, 1);
1228 
1229  // Transfer
1230  apf::Downward vtxs;
1231  int num_vts = apf_mesh->getDownward(ent, 0, vtxs);
1232  for (int kk = 0; kk < num_vts; kk++)
1233  {
1234  double mag = u_vel[kk] * u_vel[kk] + v_vel[kk] * v_vel[kk] +
1235  w_vel[kk] * w_vel[kk];
1236  mag = sqrt(mag);
1237  apf::setScalar(VelMagField, vtxs[kk], 0, mag);
1238  // Set vel
1239  double vels[3] = {u_vel[kk], v_vel[kk], w_vel[kk]};
1240  apf::setComponents(VelField, vtxs[kk], 0, vels);
1241 
1242  // Set Pr
1243  apf::setScalar(PrField, vtxs[kk], 0, pr[kk]);
1244  }
1245 
1246  int dofId = num_vts;
1247 
1248  apf::EntityShape* es = VelFieldShape->getEntityShape(apf::Mesh::TET);
1249  // Edge Dofs
1250  if (VelFieldShape->hasNodesIn(apf::Mesh::EDGE))
1251  {
1252  int ndOnEdge = VelFieldShape->countNodesOn(apf::Mesh::EDGE);
1253  Array<int> order(ndOnEdge);
1254 
1255  apf::Downward edges;
1256  int num_edge = apf_mesh->getDownward(ent, apf::Mesh::EDGE, edges);
1257  for (int ii = 0 ; ii < num_edge; ++ii)
1258  {
1259  es->alignSharedNodes(apf_mesh, ent, edges[ii], order);
1260  for (int jj = 0; jj < ndOnEdge; jj++)
1261  {
1262  int cnt = dofId + order[jj];
1263  double mag = u_vel[cnt] * u_vel[cnt] +
1264  v_vel[cnt] * v_vel[cnt] +
1265  w_vel[cnt] * w_vel[cnt];
1266  mag = sqrt(mag);
1267  apf::setScalar(VelMagField, edges[ii], jj, mag);
1268 
1269  // Set vel
1270  double vels[3] = {u_vel[cnt], v_vel[cnt], w_vel[cnt]};
1271  apf::setComponents(VelField, edges[ii], jj, vels);
1272 
1273  // Set Pr
1274  apf::setScalar(PrField, edges[ii], jj, pr[cnt]);
1275 
1276  }
1277  // Counter
1278  dofId += ndOnEdge;
1279  }
1280  }
1281  // Face Dofs
1282  if (VelFieldShape->hasNodesIn(apf::Mesh::TRIANGLE))
1283  {
1284  int ndOnFace = VelFieldShape->countNodesOn(apf::Mesh::TRIANGLE);
1285  Array<int> order(ndOnFace);
1286 
1287  apf::Downward faces;
1288  int num_face = apf_mesh->getDownward(ent, apf::Mesh::TRIANGLE, faces);
1289  for (int ii = 0; ii < num_face; ii++)
1290  {
1291  if ( ndOnFace > 1)
1292  {
1293  es->alignSharedNodes(apf_mesh, ent, faces[ii], order);
1294  }
1295  else
1296  {
1297  order[0] = 0;
1298  }
1299  for (int jj = 0; jj < ndOnFace; jj++)
1300  {
1301  int cnt = dofId + order[jj];
1302  double mag = u_vel[cnt] * u_vel[cnt] +
1303  v_vel[cnt] * v_vel[cnt] +
1304  w_vel[cnt] * w_vel[cnt];
1305  mag = sqrt(mag);
1306  apf::setScalar(VelMagField, faces[ii], jj, mag);
1307 
1308  // Set vel
1309  double vels[3] = {u_vel[cnt], v_vel[cnt], w_vel[cnt]};
1310  apf::setComponents(VelField, faces[ii], jj, vels);
1311 
1312  // Set Pr
1313  apf::setScalar(PrField, faces[ii], jj, pr[cnt]);
1314  }
1315  // Counter
1316  dofId += ndOnFace;
1317  }
1318  }
1319 
1320  iel++;
1321  }
1322  apf_mesh->end(itr);
1323 }
1324 
1325 // Transfer a scalar field its magnitude to use for mesh adaptation.
1326 void ParPumiMesh::FieldMFEMtoPUMI(apf::Mesh2* apf_mesh,
1327  ParGridFunction* grid_pr,
1328  apf::Field* PrField,
1329  apf::Field* PrMagField)
1330 {
1331  apf::FieldShape* PrFieldShape = getShape(PrField);
1332  int num_nodes = 4 * PrFieldShape->countNodesOn(0) + // Vertex
1333  6 * PrFieldShape->countNodesOn(1) + // Edge
1334  4 * PrFieldShape->countNodesOn(2) + // Triangle
1335  PrFieldShape->countNodesOn(4); // Tetrahedron
1336 
1337  // Define integration points
1338  IntegrationRule pumi_nodes(num_nodes);
1339  int ip_cnt = 0;
1340  apf::Vector3 xi_crd(0.,0.,0.);
1341 
1342  // Create a template of dof holders coordinates in parametric coordinates.
1343  // The ordering is taken care of when the field is transferred to PUMI.
1344 
1345  // Dofs on Vertices
1346  IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++);
1347  double pt_crd[3] = {0., 0., 0.};
1348  ip.Set(pt_crd, 3);
1349  for (int kk = 0; kk < 3; kk++)
1350  {
1351  IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++);
1352  double pt_crd[3] = {0.,0.,0.};
1353  pt_crd[kk] = 1.0;
1354  ip.Set(pt_crd, 3);
1355  }
1356  // Dofs on Edges
1357  if (PrFieldShape->hasNodesIn(apf::Mesh::EDGE))
1358  {
1359  const int nn = PrFieldShape->countNodesOn(apf::Mesh::EDGE);
1360  for (int ii = 0; ii < 6; ii++)
1361  {
1362  for (int jj = 0; jj < nn; jj++)
1363  {
1364  PrFieldShape->getNodeXi(apf::Mesh::EDGE, jj, xi_crd);
1365  xi_crd[0] = 0.5 * (xi_crd[0] + 1.); // from (-1,1) to (0,1)
1366  double pt_crd[3] = {0., 0., 0.};
1367  switch (ii)
1368  {
1369  case 0:
1370  pt_crd[0] = xi_crd[0];
1371  break;
1372  case 1:
1373  pt_crd[0] = 1. - xi_crd[0];
1374  pt_crd[1] = xi_crd[0];
1375  break;
1376  case 2:
1377  pt_crd[1] = xi_crd[0];
1378  break;
1379  case 3:
1380  pt_crd[2] = xi_crd[0];
1381  break;
1382  case 4:
1383  pt_crd[0] = 1. - xi_crd[0];
1384  pt_crd[2] = xi_crd[0];
1385  break;
1386  case 5:
1387  pt_crd[1] = 1. - xi_crd[0];
1388  pt_crd[2] = xi_crd[0];
1389  break;
1390  }
1391  IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++);
1392  ip.Set(pt_crd, 3);
1393  }
1394  }
1395  }
1396  // Dofs on Faces
1397  if (PrFieldShape->hasNodesIn(apf::Mesh::TRIANGLE))
1398  {
1399  const int nn = PrFieldShape->countNodesOn(apf::Mesh::TRIANGLE);
1400  for (int ii = 0; ii < 4; ii++)
1401  {
1402  for (int jj = 0; jj < nn; jj++)
1403  {
1404  PrFieldShape->getNodeXi(apf::Mesh::TRIANGLE, jj, xi_crd);
1405  double pt_crd[3] = {0., 0., 0.};
1406  switch (ii)
1407  {
1408  case 0:
1409  pt_crd[0] = xi_crd[0];
1410  pt_crd[1] = xi_crd[1];
1411  break;
1412  case 1:
1413  pt_crd[0] = xi_crd[0];
1414  pt_crd[2] = xi_crd[2];
1415  break;
1416  case 2:
1417  pt_crd[0] = xi_crd[0];
1418  pt_crd[1] = xi_crd[1];
1419  pt_crd[2] = xi_crd[2];
1420  break;
1421  case 3:
1422  pt_crd[1] = xi_crd[0];
1423  pt_crd[2] = xi_crd[1];
1424  break;
1425  }
1426  IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++);
1427  ip.Set(pt_crd, 3);
1428  }
1429  }
1430  }
1431  MFEM_ASSERT(ip_cnt == num_nodes, "");
1432 
1433  // Other dofs
1434  apf::MeshEntity* ent;
1435  apf::MeshIterator* itr = apf_mesh->begin(3);
1436  int iel = 0;
1437  while ((ent = apf_mesh->iterate(itr)))
1438  {
1439  // Get the solution
1440  Vector pr;
1441  grid_pr->GetValues(iel, pumi_nodes, pr, 1);
1442 
1443  // Transfer
1444  apf::Downward vtxs;
1445  int num_vts = apf_mesh->getDownward(ent, 0, vtxs);
1446  for (int kk = 0; kk < num_vts; kk++)
1447  {
1448  double mag;
1449  (pr[kk] >= 0. ? mag = pr[kk] : mag = -pr[kk]);
1450  apf::setScalar(PrMagField, vtxs[kk], 0, mag);
1451 
1452  // Set Pr
1453  apf::setScalar(PrField, vtxs[kk], 0, pr[kk]);
1454  }
1455 
1456  int dofId = num_vts;
1457 
1458  apf::EntityShape* es = PrFieldShape->getEntityShape(apf::Mesh::TET);
1459  // Edge Dofs
1460  if (PrFieldShape->hasNodesIn(apf::Mesh::EDGE))
1461  {
1462  int ndOnEdge = PrFieldShape->countNodesOn(apf::Mesh::EDGE);
1463  Array<int> order(ndOnEdge);
1464 
1465  apf::Downward edges;
1466  int num_edge = apf_mesh->getDownward(ent, apf::Mesh::EDGE, edges);
1467  for (int ii = 0 ; ii < num_edge; ++ii)
1468  {
1469  es->alignSharedNodes(apf_mesh, ent, edges[ii], order);
1470  for (int jj = 0; jj < ndOnEdge; jj++)
1471  {
1472  int cnt = dofId + order[jj];
1473  double mag;
1474  (pr[cnt] >= 0. ? mag = pr[cnt] : mag = -pr[cnt]);
1475  apf::setScalar(PrMagField, edges[ii], jj, mag);
1476 
1477  // Set Pr
1478  apf::setScalar(PrField, edges[ii], jj, pr[cnt]);
1479 
1480  }
1481  // Counter
1482  dofId += ndOnEdge;
1483  }
1484  }
1485 
1486  // Face Dofs
1487  if (PrFieldShape->hasNodesIn(apf::Mesh::TRIANGLE))
1488  {
1489  int ndOnFace = PrFieldShape->countNodesOn(apf::Mesh::TRIANGLE);
1490  Array<int> order(ndOnFace);
1491 
1492  apf::Downward faces;
1493  int num_face = apf_mesh->getDownward(ent, apf::Mesh::TRIANGLE, faces);
1494  for (int ii = 0; ii < num_face; ii++)
1495  {
1496  if ( ndOnFace > 1)
1497  {
1498  es->alignSharedNodes(apf_mesh, ent, faces[ii], order);
1499  }
1500  else
1501  {
1502  order[0] = 0;
1503  }
1504  for (int jj = 0; jj < ndOnFace; jj++)
1505  {
1506  int cnt = dofId + order[jj];
1507  double mag;
1508  (pr[cnt] >= 0. ? mag = pr[cnt] : mag = -pr[cnt]);
1509  apf::setScalar(PrMagField, faces[ii], jj, mag);
1510 
1511  // Set Pr
1512  apf::setScalar(PrField, faces[ii], jj, pr[cnt]);
1513  }
1514  // Counter
1515  dofId += ndOnFace;
1516  }
1517  }
1518 
1519  iel++;
1520  }
1521  apf_mesh->end(itr);
1522 }
1523 
1524 // Transfer a vector field and the magnitude of the vector field to use for mesh
1525 // adaptation
1526 void ParPumiMesh::VectorFieldMFEMtoPUMI(apf::Mesh2* apf_mesh,
1527  ParGridFunction* grid_vel,
1528  apf::Field* VelField,
1529  apf::Field* VelMagField)
1530 {
1531  apf::FieldShape* VelFieldShape = getShape(VelField);
1532  int num_nodes = 4 * VelFieldShape->countNodesOn(0) + // Vertex
1533  6 * VelFieldShape->countNodesOn(1) + // Edge
1534  4 * VelFieldShape->countNodesOn(2) + // Triangle
1535  VelFieldShape->countNodesOn(4);// Tetrahedron
1536 
1537  // Define integration points
1538  IntegrationRule pumi_nodes(num_nodes);
1539  int ip_cnt = 0;
1540  apf::Vector3 xi_crd(0.,0.,0.);
1541 
1542  // Create a template of dof holders coordinates in parametric coordinates.
1543  // The ordering is taken care of when the field is transferred to PUMI.
1544 
1545  // Dofs on Vertices
1546  IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++);
1547  double pt_crd[3] = {0., 0., 0.};
1548  ip.Set(pt_crd, 3);
1549  for (int kk = 0; kk < 3; kk++)
1550  {
1551  IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++);
1552  double pt_crd[3] = {0.,0.,0.};
1553  pt_crd[kk] = 1.0;
1554  ip.Set(pt_crd, 3);
1555  }
1556  // Dofs on Edges
1557  if (VelFieldShape->hasNodesIn(apf::Mesh::EDGE))
1558  {
1559  const int nn = VelFieldShape->countNodesOn(apf::Mesh::EDGE);
1560  for (int ii = 0; ii < 6; ii++)
1561  {
1562  for (int jj = 0; jj < nn; jj++)
1563  {
1564  VelFieldShape->getNodeXi(apf::Mesh::EDGE, jj, xi_crd);
1565  xi_crd[0] = 0.5 * (xi_crd[0] + 1.); // from (-1,1) to (0,1)
1566  double pt_crd[3] = {0., 0., 0.};
1567  switch (ii)
1568  {
1569  case 0:
1570  pt_crd[0] = xi_crd[0];
1571  break;
1572  case 1:
1573  pt_crd[0] = 1. - xi_crd[0];
1574  pt_crd[1] = xi_crd[0];
1575  break;
1576  case 2:
1577  pt_crd[1] = xi_crd[0];
1578  break;
1579  case 3:
1580  pt_crd[2] = xi_crd[0];
1581  break;
1582  case 4:
1583  pt_crd[0] = 1. - xi_crd[0];
1584  pt_crd[2] = xi_crd[0];
1585  break;
1586  case 5:
1587  pt_crd[1] = 1. - xi_crd[0];
1588  pt_crd[2] = xi_crd[0];
1589  break;
1590  }
1591  IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++);
1592  ip.Set(pt_crd, 3);
1593  }
1594  }
1595  }
1596  // Dofs on Faces
1597  if (VelFieldShape->hasNodesIn(apf::Mesh::TRIANGLE))
1598  {
1599  const int nn = VelFieldShape->countNodesOn(apf::Mesh::TRIANGLE);
1600  for (int ii = 0; ii < 4; ii++)
1601  {
1602  for (int jj = 0; jj < nn; jj++)
1603  {
1604  VelFieldShape->getNodeXi(apf::Mesh::TRIANGLE, jj, xi_crd);
1605  double pt_crd[3] = {0., 0., 0.};
1606  switch (ii)
1607  {
1608  case 0:
1609  pt_crd[0] = xi_crd[0];
1610  pt_crd[1] = xi_crd[1];
1611  break;
1612  case 1:
1613  pt_crd[0] = xi_crd[0];
1614  pt_crd[2] = xi_crd[2];
1615  break;
1616  case 2:
1617  pt_crd[0] = xi_crd[0];
1618  pt_crd[1] = xi_crd[1];
1619  pt_crd[2] = xi_crd[2];
1620  break;
1621  case 3:
1622  pt_crd[1] = xi_crd[0];
1623  pt_crd[2] = xi_crd[1];
1624  break;
1625  }
1626  IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++);
1627  ip.Set(pt_crd, 3);
1628  }
1629  }
1630  }
1631  MFEM_ASSERT(ip_cnt == num_nodes, "");
1632 
1633  // Other dofs
1634  apf::MeshEntity* ent;
1635  apf::MeshIterator* itr = apf_mesh->begin(3);
1636  int iel = 0;
1637  while ((ent = apf_mesh->iterate(itr)))
1638  {
1639  // Get the solution
1640  Vector u_vel, v_vel, w_vel;
1641  grid_vel->GetValues(iel, pumi_nodes, u_vel, 1);
1642  grid_vel->GetValues(iel, pumi_nodes, v_vel, 2);
1643  grid_vel->GetValues(iel, pumi_nodes, w_vel, 3);
1644 
1645  // Transfer
1646  apf::Downward vtxs;
1647  int num_vts = apf_mesh->getDownward(ent, 0, vtxs);
1648  for (int kk = 0; kk < num_vts; kk++)
1649  {
1650  double mag = u_vel[kk] * u_vel[kk] + v_vel[kk] * v_vel[kk] +
1651  w_vel[kk] * w_vel[kk];
1652  mag = sqrt(mag);
1653  apf::setScalar(VelMagField, vtxs[kk], 0, mag);
1654  // Set vel
1655  double vels[3] = {u_vel[kk], v_vel[kk], w_vel[kk]};
1656  apf::setComponents(VelField, vtxs[kk], 0, vels);
1657  }
1658 
1659  int dofId = num_vts;
1660 
1661  apf::EntityShape* es = VelFieldShape->getEntityShape(apf::Mesh::TET);
1662  // Edge Dofs
1663  if (VelFieldShape->hasNodesIn(apf::Mesh::EDGE))
1664  {
1665  int ndOnEdge = VelFieldShape->countNodesOn(apf::Mesh::EDGE);
1666  Array<int> order(ndOnEdge);
1667 
1668  apf::Downward edges;
1669  int num_edge = apf_mesh->getDownward(ent, apf::Mesh::EDGE, edges);
1670  for (int ii = 0 ; ii < num_edge; ++ii)
1671  {
1672  es->alignSharedNodes(apf_mesh, ent, edges[ii], order);
1673  for (int jj = 0; jj < ndOnEdge; jj++)
1674  {
1675  int cnt = dofId + order[jj];
1676  double mag = u_vel[cnt] * u_vel[cnt] +
1677  v_vel[cnt] * v_vel[cnt] +
1678  w_vel[cnt] * w_vel[cnt];
1679  mag = sqrt(mag);
1680  apf::setScalar(VelMagField, edges[ii], jj, mag);
1681 
1682  // Set vel
1683  double vels[3] = {u_vel[cnt], v_vel[cnt], w_vel[cnt]};
1684  apf::setComponents(VelField, edges[ii], jj, vels);
1685  }
1686  // Counter
1687  dofId += ndOnEdge;
1688  }
1689  }
1690 
1691  // Face Dofs
1692  if (VelFieldShape->hasNodesIn(apf::Mesh::TRIANGLE))
1693  {
1694  int ndOnFace = VelFieldShape->countNodesOn(apf::Mesh::TRIANGLE);
1695  Array<int> order(ndOnFace);
1696 
1697  apf::Downward faces;
1698  int num_face = apf_mesh->getDownward(ent, apf::Mesh::TRIANGLE, faces);
1699  for (int ii = 0; ii < num_face; ii++)
1700  {
1701  if ( ndOnFace > 1)
1702  {
1703  es->alignSharedNodes(apf_mesh, ent, faces[ii], order);
1704  }
1705  else
1706  {
1707  order[0] = 0;
1708  }
1709  for (int jj = 0; jj < ndOnFace; jj++)
1710  {
1711  int cnt = dofId + order[jj];
1712  double mag = u_vel[cnt] * u_vel[cnt] +
1713  v_vel[cnt] * v_vel[cnt] +
1714  w_vel[cnt] * w_vel[cnt];
1715  mag = sqrt(mag);
1716  apf::setScalar(VelMagField, faces[ii], jj, mag);
1717 
1718  // Set vel
1719  double vels[3] = {u_vel[cnt], v_vel[cnt], w_vel[cnt]};
1720  apf::setComponents(VelField, faces[ii], jj, vels);
1721  }
1722  // Counter
1723  dofId += ndOnFace;
1724  }
1725  }
1726 
1727  iel++;
1728  }
1729  apf_mesh->end(itr);
1730 }
1731 
1732 void ParPumiMesh::FieldPUMItoMFEM(apf::Mesh2* apf_mesh,
1733  apf::Field* ScalarField,
1734  ParGridFunction* Pr)
1735 {
1736  // Pr->Update();
1737  // Find local numbering
1738  v_num_loc = apf_mesh->findNumbering("LocalVertexNumbering");
1739 
1740  // Loop over field to copy
1741  getShape(ScalarField);
1742  apf::MeshEntity* ent;
1743  apf::MeshIterator* itr = apf_mesh->begin(0);
1744  while ((ent = apf_mesh->iterate(itr)))
1745  {
1746  unsigned int id = apf::getNumber(v_num_loc, ent, 0, 0);
1747  double fieldVal = apf::getScalar(ScalarField, ent, 0);
1748 
1749  (Pr->GetData())[id] = fieldVal;
1750  }
1751  apf_mesh->end(itr);
1752 
1753  // Check for higher order
1754  getShape(ScalarField);
1755  if ( Pr->FESpace()->GetOrder(1) > 1 )
1756  {
1757  // Assume all element type are the same i.e. tetrahedral
1758  const FiniteElement* H1_elem = Pr->FESpace()->GetFE(1);
1759  const IntegrationRule &All_nodes = H1_elem->GetNodes();
1760  int nnodes = All_nodes.Size();
1761 
1762  // Loop over elements
1763  int nc = apf::countComponents(ScalarField);
1764  int iel = 0;
1765  itr = apf_mesh->begin(3);
1766  while ((ent = apf_mesh->iterate(itr)))
1767  {
1768  Array<int> vdofs;
1769  Pr->FESpace()->GetElementVDofs(iel, vdofs);
1770 
1771  // Create PUMI element to interpolate
1772  apf::MeshElement* mE = apf::createMeshElement(apf_mesh, ent);
1773  apf::Element* elem = apf::createElement(ScalarField, mE);
1774 
1775  // Vertices are already interpolated
1776  for (int ip = 0; ip < nnodes; ip++) //num_vert
1777  {
1778  // Take parametric coordinates of the node
1779  apf::Vector3 param;
1780  param[0] = All_nodes.IntPoint(ip).x;
1781  param[1] = All_nodes.IntPoint(ip).y;
1782  param[2] = All_nodes.IntPoint(ip).z;
1783 
1784  // Compute the interpolating coordinates
1785  apf::DynamicVector phCrd(nc);
1786  apf::getComponents(elem, param, &phCrd[0]);
1787 
1788  // Fill the nodes list
1789  for (int kk = 0; kk < nc; ++kk)
1790  {
1791  int dof_ctr = ip + kk * nnodes;
1792  (Pr->GetData())[vdofs[dof_ctr]] = phCrd[kk];
1793  }
1794  }
1795  iel++;
1796  apf::destroyElement(elem);
1797  apf::destroyMeshElement(mE);
1798  }
1799  apf_mesh->end(itr);
1800  }
1801 }
1802 
1803 }
1804 
1805 #endif // MFEM_USE_MPI
1806 #endif // MFEM_USE_SCOREC
Abstract class for Finite Elements.
Definition: fe.hpp:140
void Set(const double *p, const int dim)
Definition: intrules.hpp:32
Ordering::Type GetOrdering() const
Return the ordering method.
Definition: fespace.hpp:265
int Size() const
Logical size of the array.
Definition: array.hpp:133
void Recreate(const int n, const int *p)
Definition: sets.cpp:59
Class for an integration rule - an Array of IntegrationPoint.
Definition: intrules.hpp:83
int NRanks
Definition: pmesh.hpp:42
void SetSize(int dim, int connections_per_row)
Set the size and the number of connections for the table.
Definition: table.cpp:126
virtual Element * Duplicate(Mesh *m) const =0
virtual void GetVertices(Array< int > &v) const =0
Returns element&#39;s vertices.
int GetNBE() const
Returns number of boundary elements.
Definition: mesh.hpp:621
void GetElementVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom in array dofs for i&#39;th element.
Definition: fespace.cpp:171
const Geometry::Type geom
Definition: ex1.cpp:40
int BaseGeom
Definition: mesh.hpp:59
Array< int > sface_lface
Definition: pmesh.hpp:55
void SetDims(int rows, int nnz)
Definition: table.cpp:142
void Copy(Array &copy) const
Create a copy of the current array.
Definition: array.hpp:190
Class for PUMI grid functions.
Definition: pumi.hpp:118
int VectorDim() const
Definition: gridfunc.cpp:291
GridFunction * Nodes
Definition: mesh.hpp:151
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
Definition: table.cpp:189
int GetNE() const
Returns number of elements.
Definition: mesh.hpp:618
Abstract parallel finite element space.
Definition: pfespace.hpp:28
T * end() const
Definition: array.hpp:267
int BaseBdrGeom
Definition: mesh.hpp:59
double * GetData() const
Return a pointer to the beginning of the Vector data.
Definition: vector.hpp:129
Array< Element * > faces
Definition: mesh.hpp:75
Array< int > sedge_ledge
Definition: pmesh.hpp:54
Table * el_to_face
Definition: mesh.hpp:133
ParNCMesh * pncmesh
Definition: pmesh.hpp:140
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition: intrules.hpp:235
MPI_Comm MyComm
Definition: pmesh.hpp:41
Symmetric 3D Table.
Definition: stable3d.hpp:28
Array< Element * > shared_edges
Definition: pmesh.hpp:44
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
Definition: error.cpp:146
const IntegrationRule & GetNodes() const
Definition: fe.hpp:270
int Insert(IntegerSet &s)
Definition: sets.cpp:82
Array< Element * > shared_faces
Definition: pmesh.hpp:45
const Element * GetElement(int i) const
Definition: mesh.hpp:676
void Sort()
Sorts the array. This requires operator&lt; to be defined for T.
Definition: array.hpp:237
void GetValues(int i, const IntegrationRule &ir, Vector &vals, int vdim=1) const
Definition: gridfunc.cpp:434
int FindSorted(const T &el) const
Do bisection search for &#39;el&#39; in a sorted array; return -1 if not found.
Definition: array.hpp:683
int GetVDim() const
Returns vector dimension.
Definition: fespace.hpp:242
int Size() const
Returns the number of TYPE I elements.
Definition: table.hpp:92
FiniteElementSpace * FESpace()
Definition: gridfunc.hpp:337
int Dimension() const
Definition: mesh.hpp:645
Table * el_to_edge
Definition: mesh.hpp:132
void Copy(GroupTopology &copy) const
Copy.
int SpaceDimension() const
Definition: mesh.hpp:646
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition: mesh.hpp:174
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition: fespace.hpp:66
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
Definition: globals.hpp:69
void SetSize(int nsize)
Change logical size of the array, keep existing entries.
Definition: array.hpp:569
Array< Vertex > vertices
Definition: mesh.hpp:73
int GetOrder(int i) const
Returns the order of the i&#39;th finite element.
Definition: fespace.cpp:94
int meshgen
Definition: mesh.hpp:61
Table * bel_to_edge
Definition: mesh.hpp:136
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition: mesh.hpp:176
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition: mesh.hpp:615
Array< int > be_to_edge
Definition: mesh.hpp:135
virtual const char * Name() const
Definition: fe_coll.hpp:50
Class for integration point with weight.
Definition: intrules.hpp:25
Table group_sedge
Definition: pmesh.hpp:49
A set of integers.
Definition: sets.hpp:23
Table group_svert
Shared objects in each group.
Definition: pmesh.hpp:48
Table * edge_vertex
Definition: mesh.hpp:139
const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement associated with i&#39;th element.
Definition: fespace.cpp:1335
Array< FaceInfo > faces_info
Definition: mesh.hpp:129
virtual int GetNVertices() const =0
void SetAttribute(const int attr)
Set element&#39;s attribute.
Definition: element.hpp:53
NCMesh * ncmesh
Optional non-conforming mesh extension.
Definition: mesh.hpp:177
int Dim
Definition: mesh.hpp:53
int GetNEdges() const
Return the number of edges.
Definition: mesh.hpp:624
int GetNFaces() const
Return the number of faces in a 3D mesh.
Definition: mesh.hpp:627
Vector data type.
Definition: vector.hpp:48
const FiniteElementCollection * FEColl() const
Definition: fespace.hpp:267
Arbitrary order H1-conforming (continuous) finite elements.
Definition: fe_coll.hpp:79
Array< int > svert_lvert
Shared to local index mapping.
Definition: pmesh.hpp:53
int MyRank
Definition: pmesh.hpp:42
int spaceDim
Definition: mesh.hpp:54
Class for parallel grid function.
Definition: pgridfunc.hpp:32
Table group_sface
Definition: pmesh.hpp:50
List of integer sets.
Definition: sets.hpp:54
Array< int > be_to_face
Definition: mesh.hpp:137
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition: globals.hpp:64
GroupTopology gtopo
Definition: pmesh.hpp:127
Class for parallel meshes.
Definition: pmesh.hpp:32
Abstract data type element.
Definition: element.hpp:27
Data type line segment element.
Definition: segment.hpp:22
void Copy(Table &copy) const
Definition: table.cpp:381
Array< int > attributes
A list of all unique element attributes used by the Mesh.
Definition: mesh.hpp:172
const Element * GetBdrElement(int i) const
Definition: mesh.hpp:680