MFEM  v4.2.0
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
mesh_readers.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 
12 #include "mesh_headers.hpp"
13 #include "../fem/fem.hpp"
14 #include "../general/text.hpp"
15 #include "gmsh.hpp"
16 
17 #include <iostream>
18 #include <cstdio>
19 
20 #ifdef MFEM_USE_NETCDF
21 #include "netcdf.h"
22 #endif
23 
24 using namespace std;
25 
26 namespace mfem
27 {
28 
29 bool Mesh::remove_unused_vertices = true;
30 
31 void Mesh::ReadMFEMMesh(std::istream &input, bool mfem_v11, int &curved)
32 {
33  // Read MFEM mesh v1.0 format
34  string ident;
35 
36  // read lines beginning with '#' (comments)
37  skip_comment_lines(input, '#');
38  input >> ident; // 'dimension'
39 
40  MFEM_VERIFY(ident == "dimension", "invalid mesh file");
41  input >> Dim;
42 
43  skip_comment_lines(input, '#');
44  input >> ident; // 'elements'
45 
46  MFEM_VERIFY(ident == "elements", "invalid mesh file");
47  input >> NumOfElements;
48  elements.SetSize(NumOfElements);
49  for (int j = 0; j < NumOfElements; j++)
50  {
51  elements[j] = ReadElement(input);
52  }
53 
54  skip_comment_lines(input, '#');
55  input >> ident; // 'boundary'
56 
57  MFEM_VERIFY(ident == "boundary", "invalid mesh file");
58  input >> NumOfBdrElements;
59  boundary.SetSize(NumOfBdrElements);
60  for (int j = 0; j < NumOfBdrElements; j++)
61  {
62  boundary[j] = ReadElement(input);
63  }
64 
65  skip_comment_lines(input, '#');
66  input >> ident;
67 
68  if (mfem_v11 && ident == "vertex_parents")
69  {
70  ncmesh = new NCMesh(this, &input);
71  // NOTE: the constructor above will call LoadVertexParents
72 
73  skip_comment_lines(input, '#');
74  input >> ident;
75 
76  if (ident == "coarse_elements")
77  {
78  ncmesh->LoadCoarseElements(input);
79 
80  skip_comment_lines(input, '#');
81  input >> ident;
82  }
83  }
84 
85  MFEM_VERIFY(ident == "vertices", "invalid mesh file");
86  input >> NumOfVertices;
87  vertices.SetSize(NumOfVertices);
88 
89  input >> ws >> ident;
90  if (ident != "nodes")
91  {
92  // read the vertices
93  spaceDim = atoi(ident.c_str());
94  for (int j = 0; j < NumOfVertices; j++)
95  {
96  for (int i = 0; i < spaceDim; i++)
97  {
98  input >> vertices[j](i);
99  }
100  }
101 
102  // initialize vertex positions in NCMesh
103  if (ncmesh) { ncmesh->SetVertexPositions(vertices); }
104  }
105  else
106  {
107  // prepare to read the nodes
108  input >> ws;
109  curved = 1;
110  }
111 
112  // When visualizing solutions on non-conforming grids, PETSc
113  // may dump additional vertices
114  if (remove_unused_vertices) { RemoveUnusedVertices(); }
115 }
116 
117 void Mesh::ReadLineMesh(std::istream &input)
118 {
119  int j,p1,p2,a;
120 
121  Dim = 1;
122 
123  input >> NumOfVertices;
124  vertices.SetSize(NumOfVertices);
125  // Sets vertices and the corresponding coordinates
126  for (j = 0; j < NumOfVertices; j++)
127  {
128  input >> vertices[j](0);
129  }
130 
131  input >> NumOfElements;
132  elements.SetSize(NumOfElements);
133  // Sets elements and the corresponding indices of vertices
134  for (j = 0; j < NumOfElements; j++)
135  {
136  input >> a >> p1 >> p2;
137  elements[j] = new Segment(p1-1, p2-1, a);
138  }
139 
140  int ind[1];
141  input >> NumOfBdrElements;
142  boundary.SetSize(NumOfBdrElements);
143  for (j = 0; j < NumOfBdrElements; j++)
144  {
145  input >> a >> ind[0];
146  ind[0]--;
147  boundary[j] = new Point(ind,a);
148  }
149 }
150 
151 void Mesh::ReadNetgen2DMesh(std::istream &input, int &curved)
152 {
153  int ints[32], attr, n;
154 
155  // Read planar mesh in Netgen format.
156  Dim = 2;
157 
158  // Read the boundary elements.
159  input >> NumOfBdrElements;
160  boundary.SetSize(NumOfBdrElements);
161  for (int i = 0; i < NumOfBdrElements; i++)
162  {
163  input >> attr
164  >> ints[0] >> ints[1];
165  ints[0]--; ints[1]--;
166  boundary[i] = new Segment(ints, attr);
167  }
168 
169  // Read the elements.
170  input >> NumOfElements;
171  elements.SetSize(NumOfElements);
172  for (int i = 0; i < NumOfElements; i++)
173  {
174  input >> attr >> n;
175  for (int j = 0; j < n; j++)
176  {
177  input >> ints[j];
178  ints[j]--;
179  }
180  switch (n)
181  {
182  case 2:
183  elements[i] = new Segment(ints, attr);
184  break;
185  case 3:
186  elements[i] = new Triangle(ints, attr);
187  break;
188  case 4:
189  elements[i] = new Quadrilateral(ints, attr);
190  break;
191  }
192  }
193 
194  if (!curved)
195  {
196  // Read the vertices.
197  input >> NumOfVertices;
198  vertices.SetSize(NumOfVertices);
199  for (int i = 0; i < NumOfVertices; i++)
200  for (int j = 0; j < Dim; j++)
201  {
202  input >> vertices[i](j);
203  }
204  }
205  else
206  {
207  input >> NumOfVertices;
208  vertices.SetSize(NumOfVertices);
209  input >> ws;
210  }
211 }
212 
213 void Mesh::ReadNetgen3DMesh(std::istream &input)
214 {
215  int ints[32], attr;
216 
217  // Read a Netgen format mesh of tetrahedra.
218  Dim = 3;
219 
220  // Read the vertices
221  input >> NumOfVertices;
222 
223  vertices.SetSize(NumOfVertices);
224  for (int i = 0; i < NumOfVertices; i++)
225  for (int j = 0; j < Dim; j++)
226  {
227  input >> vertices[i](j);
228  }
229 
230  // Read the elements
231  input >> NumOfElements;
232  elements.SetSize(NumOfElements);
233  for (int i = 0; i < NumOfElements; i++)
234  {
235  input >> attr;
236  for (int j = 0; j < 4; j++)
237  {
238  input >> ints[j];
239  ints[j]--;
240  }
241 #ifdef MFEM_USE_MEMALLOC
242  Tetrahedron *tet;
243  tet = TetMemory.Alloc();
244  tet->SetVertices(ints);
245  tet->SetAttribute(attr);
246  elements[i] = tet;
247 #else
248  elements[i] = new Tetrahedron(ints, attr);
249 #endif
250  }
251 
252  // Read the boundary information.
253  input >> NumOfBdrElements;
254  boundary.SetSize(NumOfBdrElements);
255  for (int i = 0; i < NumOfBdrElements; i++)
256  {
257  input >> attr;
258  for (int j = 0; j < 3; j++)
259  {
260  input >> ints[j];
261  ints[j]--;
262  }
263  boundary[i] = new Triangle(ints, attr);
264  }
265 }
266 
267 void Mesh::ReadTrueGridMesh(std::istream &input)
268 {
269  int i, j, ints[32], attr;
270  const int buflen = 1024;
271  char buf[buflen];
272 
273  // TODO: find the actual dimension
274  Dim = 3;
275 
276  if (Dim == 2)
277  {
278  int vari;
279  double varf;
280 
281  input >> vari >> NumOfVertices >> vari >> vari >> NumOfElements;
282  input.getline(buf, buflen);
283  input.getline(buf, buflen);
284  input >> vari;
285  input.getline(buf, buflen);
286  input.getline(buf, buflen);
287  input.getline(buf, buflen);
288 
289  // Read the vertices.
290  vertices.SetSize(NumOfVertices);
291  for (i = 0; i < NumOfVertices; i++)
292  {
293  input >> vari >> varf >> vertices[i](0) >> vertices[i](1);
294  input.getline(buf, buflen);
295  }
296 
297  // Read the elements.
298  elements.SetSize(NumOfElements);
299  for (i = 0; i < NumOfElements; i++)
300  {
301  input >> vari >> attr;
302  for (j = 0; j < 4; j++)
303  {
304  input >> ints[j];
305  ints[j]--;
306  }
307  input.getline(buf, buflen);
308  input.getline(buf, buflen);
309  elements[i] = new Quadrilateral(ints, attr);
310  }
311  }
312  else if (Dim == 3)
313  {
314  int vari;
315  double varf;
316  input >> vari >> NumOfVertices >> NumOfElements;
317  input.getline(buf, buflen);
318  input.getline(buf, buflen);
319  input >> vari >> vari >> NumOfBdrElements;
320  input.getline(buf, buflen);
321  input.getline(buf, buflen);
322  input.getline(buf, buflen);
323  // Read the vertices.
324  vertices.SetSize(NumOfVertices);
325  for (i = 0; i < NumOfVertices; i++)
326  {
327  input >> vari >> varf >> vertices[i](0) >> vertices[i](1)
328  >> vertices[i](2);
329  input.getline(buf, buflen);
330  }
331  // Read the elements.
332  elements.SetSize(NumOfElements);
333  for (i = 0; i < NumOfElements; i++)
334  {
335  input >> vari >> attr;
336  for (j = 0; j < 8; j++)
337  {
338  input >> ints[j];
339  ints[j]--;
340  }
341  input.getline(buf, buflen);
342  elements[i] = new Hexahedron(ints, attr);
343  }
344  // Read the boundary elements.
345  boundary.SetSize(NumOfBdrElements);
346  for (i = 0; i < NumOfBdrElements; i++)
347  {
348  input >> attr;
349  for (j = 0; j < 4; j++)
350  {
351  input >> ints[j];
352  ints[j]--;
353  }
354  input.getline(buf, buflen);
355  boundary[i] = new Quadrilateral(ints, attr);
356  }
357  }
358 }
359 
360 // see Tetrahedron::edges
361 const int Mesh::vtk_quadratic_tet[10] =
362 { 0, 1, 2, 3, 4, 7, 5, 6, 8, 9 };
363 
364 // see Wedge::edges & Mesh::GenerateFaces
365 // https://www.vtk.org/doc/nightly/html/classvtkBiQuadraticQuadraticWedge.html
366 const int Mesh::vtk_quadratic_wedge[18] =
367 { 0, 2, 1, 3, 5, 4, 8, 7, 6, 11, 10, 9, 12, 14, 13, 17, 16, 15};
368 
369 // see Hexahedron::edges & Mesh::GenerateFaces
370 const int Mesh::vtk_quadratic_hex[27] =
371 {
372  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
373  24, 22, 21, 23, 20, 25, 26
374 };
375 
376 void Mesh::ReadVTKMesh(std::istream &input, int &curved, int &read_gf,
377  bool &finalize_topo)
378 {
379  // VTK resources:
380  // * https://www.vtk.org/doc/nightly/html/vtkCellType_8h_source.html
381  // * https://www.vtk.org/doc/nightly/html/classvtkCell.html
382  // * https://lorensen.github.io/VTKExamples/site/VTKFileFormats
383  // * https://www.kitware.com/products/books/VTKUsersGuide.pdf
384 
385  int i, j, n, attr;
386 
387  string buff;
388  getline(input, buff); // comment line
389  getline(input, buff);
390  filter_dos(buff);
391  if (buff != "ASCII")
392  {
393  MFEM_ABORT("VTK mesh is not in ASCII format!");
394  return;
395  }
396  getline(input, buff);
397  filter_dos(buff);
398  if (buff != "DATASET UNSTRUCTURED_GRID")
399  {
400  MFEM_ABORT("VTK mesh is not UNSTRUCTURED_GRID!");
401  return;
402  }
403 
404  // Read the points, skipping optional sections such as the FIELD data from
405  // VisIt's VTK export (or from Mesh::PrintVTK with field_data==1).
406  do
407  {
408  input >> buff;
409  if (!input.good())
410  {
411  MFEM_ABORT("VTK mesh does not have POINTS data!");
412  }
413  }
414  while (buff != "POINTS");
415  int np = 0;
416  Vector points;
417  {
418  input >> np >> ws;
419  points.SetSize(3*np);
420  getline(input, buff); // "double"
421  for (i = 0; i < points.Size(); i++)
422  {
423  input >> points(i);
424  }
425  }
426 
427  // Read the cells
428  NumOfElements = n = 0;
429  Array<int> cells_data;
430  input >> ws >> buff;
431  if (buff == "CELLS")
432  {
433  input >> NumOfElements >> n >> ws;
434  cells_data.SetSize(n);
435  for (i = 0; i < n; i++)
436  {
437  input >> cells_data[i];
438  }
439  }
440 
441  // Read the cell types
442  Dim = -1;
443  int order = -1;
444  input >> ws >> buff;
445  if (buff == "CELL_TYPES")
446  {
447  input >> NumOfElements;
448  elements.SetSize(NumOfElements);
449  for (j = i = 0; i < NumOfElements; i++)
450  {
451  int ct, elem_dim, elem_order = 1;
452  input >> ct;
453  switch (ct)
454  {
455  case 5: // triangle
456  elem_dim = 2;
457  elements[i] = new Triangle(&cells_data[j+1]);
458  break;
459  case 9: // quadrilateral
460  elem_dim = 2;
461  elements[i] = new Quadrilateral(&cells_data[j+1]);
462  break;
463  case 10: // tetrahedron
464  elem_dim = 3;
465 #ifdef MFEM_USE_MEMALLOC
466  elements[i] = TetMemory.Alloc();
467  elements[i]->SetVertices(&cells_data[j+1]);
468 #else
469  elements[i] = new Tetrahedron(&cells_data[j+1]);
470 #endif
471  break;
472  case 12: // hexahedron
473  elem_dim = 3;
474  elements[i] = new Hexahedron(&cells_data[j+1]);
475  break;
476  case 13: // wedge
477  elem_dim = 3;
478  // switch between vtk vertex ordering and mfem vertex ordering:
479  // swap vertices (1,2) and (4,5)
480  elements[i] =
481  new Wedge(cells_data[j+1], cells_data[j+3], cells_data[j+2],
482  cells_data[j+4], cells_data[j+6], cells_data[j+5]);
483  break;
484 
485  case 22: // quadratic triangle
486  elem_dim = 2;
487  elem_order = 2;
488  elements[i] = new Triangle(&cells_data[j+1]);
489  break;
490  case 28: // biquadratic quadrilateral
491  elem_dim = 2;
492  elem_order = 2;
493  elements[i] = new Quadrilateral(&cells_data[j+1]);
494  break;
495  case 24: // quadratic tetrahedron
496  elem_dim = 3;
497  elem_order = 2;
498 #ifdef MFEM_USE_MEMALLOC
499  elements[i] = TetMemory.Alloc();
500  elements[i]->SetVertices(&cells_data[j+1]);
501 #else
502  elements[i] = new Tetrahedron(&cells_data[j+1]);
503 #endif
504  break;
505  case 32: // biquadratic-quadratic wedge
506  elem_dim = 3;
507  elem_order = 2;
508  // switch between vtk vertex ordering and mfem vertex ordering:
509  // swap vertices (1,2) and (4,5)
510  elements[i] =
511  new Wedge(cells_data[j+1], cells_data[j+3], cells_data[j+2],
512  cells_data[j+4], cells_data[j+6], cells_data[j+5]);
513  break;
514  case 29: // triquadratic hexahedron
515  elem_dim = 3;
516  elem_order = 2;
517  elements[i] = new Hexahedron(&cells_data[j+1]);
518  break;
519  default:
520  MFEM_ABORT("VTK mesh : cell type " << ct << " is not supported!");
521  return;
522  }
523  MFEM_VERIFY(Dim == -1 || Dim == elem_dim,
524  "elements with different dimensions are not supported");
525  MFEM_VERIFY(order == -1 || order == elem_order,
526  "elements with different orders are not supported");
527  Dim = elem_dim;
528  order = elem_order;
529  j += cells_data[j] + 1;
530  }
531  }
532 
533  // Read attributes
534  streampos sp = input.tellg();
535  input >> ws >> buff;
536  if (buff == "CELL_DATA")
537  {
538  input >> n >> ws;
539  getline(input, buff);
540  filter_dos(buff);
541  // "SCALARS material dataType numComp"
542  if (!strncmp(buff.c_str(), "SCALARS material", 16))
543  {
544  getline(input, buff); // "LOOKUP_TABLE default"
545  for (i = 0; i < NumOfElements; i++)
546  {
547  input >> attr;
548  elements[i]->SetAttribute(attr);
549  }
550  }
551  else
552  {
553  input.seekg(sp);
554  }
555  }
556  else
557  {
558  input.seekg(sp);
559  }
560 
561  if (order == 1)
562  {
563  cells_data.DeleteAll();
564  NumOfVertices = np;
565  vertices.SetSize(np);
566  for (i = 0; i < np; i++)
567  {
568  vertices[i](0) = points(3*i+0);
569  vertices[i](1) = points(3*i+1);
570  vertices[i](2) = points(3*i+2);
571  }
572  points.Destroy();
573 
574  // No boundary is defined in a VTK mesh
575  NumOfBdrElements = 0;
576  }
577  else if (order == 2)
578  {
579  curved = 1;
580 
581  // generate new enumeration for the vertices
582  Array<int> pts_dof(np);
583  pts_dof = -1;
584  for (n = i = 0; i < NumOfElements; i++)
585  {
586  int *v = elements[i]->GetVertices();
587  int nv = elements[i]->GetNVertices();
588  for (j = 0; j < nv; j++)
589  if (pts_dof[v[j]] == -1)
590  {
591  pts_dof[v[j]] = n++;
592  }
593  }
594  // keep the original ordering of the vertices
595  for (n = i = 0; i < np; i++)
596  if (pts_dof[i] != -1)
597  {
598  pts_dof[i] = n++;
599  }
600  // update the element vertices
601  for (i = 0; i < NumOfElements; i++)
602  {
603  int *v = elements[i]->GetVertices();
604  int nv = elements[i]->GetNVertices();
605  for (j = 0; j < nv; j++)
606  {
607  v[j] = pts_dof[v[j]];
608  }
609  }
610  // Define the 'vertices' from the 'points' through the 'pts_dof' map
611  NumOfVertices = n;
612  vertices.SetSize(n);
613  for (i = 0; i < np; i++)
614  {
615  if ((j = pts_dof[i]) != -1)
616  {
617  vertices[j](0) = points(3*i+0);
618  vertices[j](1) = points(3*i+1);
619  vertices[j](2) = points(3*i+2);
620  }
621  }
622 
623  // No boundary is defined in a VTK mesh
624  NumOfBdrElements = 0;
625 
626  // Generate faces and edges so that we can define quadratic
627  // FE space on the mesh
628  FinalizeTopology();
629  finalize_topo = false;
630 
631  // Define quadratic FE space
633  FiniteElementSpace *fes = new FiniteElementSpace(this, fec, Dim);
634  Nodes = new GridFunction(fes);
635  Nodes->MakeOwner(fec); // Nodes will destroy 'fec' and 'fes'
636  own_nodes = 1;
637 
638  // Map vtk points to edge/face/element dofs
639  Array<int> dofs;
640  for (n = i = 0; i < NumOfElements; i++)
641  {
642  fes->GetElementDofs(i, dofs);
643  const int *vtk_mfem;
644  switch (elements[i]->GetGeometryType())
645  {
646  case Geometry::TRIANGLE:
647  case Geometry::SQUARE:
648  vtk_mfem = vtk_quadratic_hex; break; // identity map
649  case Geometry::TETRAHEDRON:
650  vtk_mfem = vtk_quadratic_tet; break;
651  case Geometry::CUBE:
652  vtk_mfem = vtk_quadratic_hex; break;
653  case Geometry::PRISM:
654  vtk_mfem = vtk_quadratic_wedge; break;
655  default:
656  vtk_mfem = NULL; // suppress a warning
657  break;
658  }
659 
660  for (n++, j = 0; j < dofs.Size(); j++, n++)
661  {
662  if (pts_dof[cells_data[n]] == -1)
663  {
664  pts_dof[cells_data[n]] = dofs[vtk_mfem[j]];
665  }
666  else
667  {
668  if (pts_dof[cells_data[n]] != dofs[vtk_mfem[j]])
669  {
670  MFEM_ABORT("VTK mesh : inconsistent quadratic mesh!");
671  }
672  }
673  }
674  }
675 
676  // Define the 'Nodes' from the 'points' through the 'pts_dof' map
677  for (i = 0; i < np; i++)
678  {
679  dofs.SetSize(1);
680  if ((dofs[0] = pts_dof[i]) != -1)
681  {
682  fes->DofsToVDofs(dofs);
683  for (j = 0; j < dofs.Size(); j++)
684  {
685  (*Nodes)(dofs[j]) = points(3*i+j);
686  }
687  }
688  }
689 
690  read_gf = 0;
691  }
692 }
693 
694 void Mesh::ReadNURBSMesh(std::istream &input, int &curved, int &read_gf)
695 {
696  NURBSext = new NURBSExtension(input);
697 
698  Dim = NURBSext->Dimension();
699  NumOfVertices = NURBSext->GetNV();
700  NumOfElements = NURBSext->GetNE();
701  NumOfBdrElements = NURBSext->GetNBE();
702 
703  NURBSext->GetElementTopo(elements);
704  NURBSext->GetBdrElementTopo(boundary);
705 
706  vertices.SetSize(NumOfVertices);
707  curved = 1;
708  if (NURBSext->HavePatches())
709  {
710  NURBSFECollection *fec = new NURBSFECollection(NURBSext->GetOrder());
711  FiniteElementSpace *fes = new FiniteElementSpace(this, fec, Dim,
712  Ordering::byVDIM);
713  Nodes = new GridFunction(fes);
714  Nodes->MakeOwner(fec);
715  NURBSext->SetCoordsFromPatches(*Nodes);
716  own_nodes = 1;
717  read_gf = 0;
718  int vd = Nodes->VectorDim();
719  for (int i = 0; i < vd; i++)
720  {
721  Vector vert_val;
722  Nodes->GetNodalValues(vert_val, i+1);
723  for (int j = 0; j < NumOfVertices; j++)
724  {
725  vertices[j](i) = vert_val(j);
726  }
727  }
728  }
729  else
730  {
731  read_gf = 1;
732  }
733 }
734 
735 void Mesh::ReadInlineMesh(std::istream &input, bool generate_edges)
736 {
737  // Initialize to negative numbers so that we know if they've been set. We're
738  // using Element::POINT as our flag, since we're not going to make a 0D mesh,
739  // ever.
740  int nx = -1;
741  int ny = -1;
742  int nz = -1;
743  double sx = -1.0;
744  double sy = -1.0;
745  double sz = -1.0;
746  Element::Type type = Element::POINT;
747 
748  while (true)
749  {
750  skip_comment_lines(input, '#');
751  // Break out if we reached the end of the file after gobbling up the
752  // whitespace and comments after the last keyword.
753  if (!input.good())
754  {
755  break;
756  }
757 
758  // Read the next keyword
759  std::string name;
760  input >> name;
761  input >> std::ws;
762  // Make sure there's an equal sign
763  MFEM_VERIFY(input.get() == '=',
764  "Inline mesh expected '=' after keyword " << name);
765  input >> std::ws;
766 
767  if (name == "nx")
768  {
769  input >> nx;
770  }
771  else if (name == "ny")
772  {
773  input >> ny;
774  }
775  else if (name == "nz")
776  {
777  input >> nz;
778  }
779  else if (name == "sx")
780  {
781  input >> sx;
782  }
783  else if (name == "sy")
784  {
785  input >> sy;
786  }
787  else if (name == "sz")
788  {
789  input >> sz;
790  }
791  else if (name == "type")
792  {
793  std::string eltype;
794  input >> eltype;
795  if (eltype == "segment")
796  {
797  type = Element::SEGMENT;
798  }
799  else if (eltype == "quad")
800  {
801  type = Element::QUADRILATERAL;
802  }
803  else if (eltype == "tri")
804  {
805  type = Element::TRIANGLE;
806  }
807  else if (eltype == "hex")
808  {
809  type = Element::HEXAHEDRON;
810  }
811  else if (eltype == "wedge")
812  {
813  type = Element::WEDGE;
814  }
815  else if (eltype == "tet")
816  {
817  type = Element::TETRAHEDRON;
818  }
819  else
820  {
821  MFEM_ABORT("unrecognized element type (read '" << eltype
822  << "') in inline mesh format. "
823  "Allowed: segment, tri, quad, tet, hex, wedge");
824  }
825  }
826  else
827  {
828  MFEM_ABORT("unrecognized keyword (" << name
829  << ") in inline mesh format. "
830  "Allowed: nx, ny, nz, type, sx, sy, sz");
831  }
832 
833  input >> std::ws;
834  // Allow an optional semi-colon at the end of each line.
835  if (input.peek() == ';')
836  {
837  input.get();
838  }
839 
840  // Done reading file
841  if (!input)
842  {
843  break;
844  }
845  }
846 
847  // Now make the mesh.
848  if (type == Element::SEGMENT)
849  {
850  MFEM_VERIFY(nx > 0 && sx > 0.0,
851  "invalid 1D inline mesh format, all values must be "
852  "positive\n"
853  << " nx = " << nx << "\n"
854  << " sx = " << sx << "\n");
855  Make1D(nx, sx);
856  }
857  else if (type == Element::TRIANGLE || type == Element::QUADRILATERAL)
858  {
859  MFEM_VERIFY(nx > 0 && ny > 0 && sx > 0.0 && sy > 0.0,
860  "invalid 2D inline mesh format, all values must be "
861  "positive\n"
862  << " nx = " << nx << "\n"
863  << " ny = " << ny << "\n"
864  << " sx = " << sx << "\n"
865  << " sy = " << sy << "\n");
866  Make2D(nx, ny, type, sx, sy, generate_edges, true);
867  }
868  else if (type == Element::TETRAHEDRON || type == Element::WEDGE ||
869  type == Element::HEXAHEDRON)
870  {
871  MFEM_VERIFY(nx > 0 && ny > 0 && nz > 0 &&
872  sx > 0.0 && sy > 0.0 && sz > 0.0,
873  "invalid 3D inline mesh format, all values must be "
874  "positive\n"
875  << " nx = " << nx << "\n"
876  << " ny = " << ny << "\n"
877  << " nz = " << nz << "\n"
878  << " sx = " << sx << "\n"
879  << " sy = " << sy << "\n"
880  << " sz = " << sz << "\n");
881  Make3D(nx, ny, nz, type, sx, sy, sz, true);
882  // TODO: maybe have an option in the file to control ordering?
883  }
884  else
885  {
886  MFEM_ABORT("For inline mesh, must specify an element type ="
887  " [segment, tri, quad, tet, hex, wedge]");
888  }
889 }
890 
891 void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
892 {
893  string buff;
894  double version;
895  int binary, dsize;
896  input >> version >> binary >> dsize;
897  if (version < 2.2)
898  {
899  MFEM_ABORT("Gmsh file version < 2.2");
900  }
901  if (dsize != sizeof(double))
902  {
903  MFEM_ABORT("Gmsh file : dsize != sizeof(double)");
904  }
905  getline(input, buff);
906  // There is a number 1 in binary format
907  if (binary)
908  {
909  int one;
910  input.read(reinterpret_cast<char*>(&one), sizeof(one));
911  if (one != 1)
912  {
913  MFEM_ABORT("Gmsh file : wrong binary format");
914  }
915  }
916 
917  // A map between a serial number of the vertex and its number in the file
918  // (there may be gaps in the numbering, and also Gmsh enumerates vertices
919  // starting from 1, not 0)
920  map<int, int> vertices_map;
921 
922  // Gmsh always outputs coordinates in 3D, but MFEM distinguishes between the
923  // mesh element dimension (Dim) and the dimension of the space in which the
924  // mesh is embedded (spaceDim). For example, a 2D MFEM mesh has Dim = 2 and
925  // spaceDim = 2, while a 2D surface mesh in 3D has Dim = 2 but spaceDim = 3.
926  // Below we set spaceDim by measuring the mesh bounding box and checking for
927  // a lower dimensional subspace. The assumption is that the mesh is at least
928  // 2D if the y-dimension of the box is non-trivial and 3D if the z-dimension
929  // is non-trivial. Note that with these assumptions a 2D mesh parallel to the
930  // yz plane will be considered a surface mesh embedded in 3D whereas the same
931  // 2D mesh parallel to the xy plane will be considered a 2D mesh.
932  double bb_tol = 1e-14;
933  double bb_min[3];
934  double bb_max[3];
935 
936  // Mesh order
937  int mesh_order = 1;
938 
939  // Mesh type
940  bool periodic = false;
941 
942  // Vector field to store uniformly spaced Gmsh high order mesh coords
943  GridFunction Nodes_gf;
944 
945  // Read the lines of the mesh file. If we face specific keyword, we'll treat
946  // the section.
947  while (input >> buff)
948  {
949  if (buff == "$Nodes") // reading mesh vertices
950  {
951  input >> NumOfVertices;
952  getline(input, buff);
953  vertices.SetSize(NumOfVertices);
954  int serial_number;
955  const int gmsh_dim = 3; // Gmsh always outputs 3 coordinates
956  double coord[gmsh_dim];
957  for (int ver = 0; ver < NumOfVertices; ++ver)
958  {
959  if (binary)
960  {
961  input.read(reinterpret_cast<char*>(&serial_number), sizeof(int));
962  input.read(reinterpret_cast<char*>(coord), gmsh_dim*sizeof(double));
963  }
964  else // ASCII
965  {
966  input >> serial_number;
967  for (int ci = 0; ci < gmsh_dim; ++ci)
968  {
969  input >> coord[ci];
970  }
971  }
972  vertices[ver] = Vertex(coord, gmsh_dim);
973  vertices_map[serial_number] = ver;
974 
975  for (int ci = 0; ci < gmsh_dim; ++ci)
976  {
977  bb_min[ci] = (ver == 0) ? coord[ci] :
978  std::min(bb_min[ci], coord[ci]);
979  bb_max[ci] = (ver == 0) ? coord[ci] :
980  std::max(bb_max[ci], coord[ci]);
981  }
982  }
983  double bb_size = std::max(bb_max[0] - bb_min[0],
984  std::max(bb_max[1] - bb_min[1],
985  bb_max[2] - bb_min[2]));
986  spaceDim = 1;
987  if (bb_max[1] - bb_min[1] > bb_size * bb_tol)
988  {
989  spaceDim++;
990  }
991  if (bb_max[2] - bb_min[2] > bb_size * bb_tol)
992  {
993  spaceDim++;
994  }
995 
996  if (static_cast<int>(vertices_map.size()) != NumOfVertices)
997  {
998  MFEM_ABORT("Gmsh file : vertices indices are not unique");
999  }
1000  } // section '$Nodes'
1001  else if (buff == "$Elements") // reading mesh elements
1002  {
1003  int num_of_all_elements;
1004  input >> num_of_all_elements;
1005  // = NumOfElements + NumOfBdrElements + (maybe, PhysicalPoints)
1006  getline(input, buff);
1007 
1008  int serial_number; // serial number of an element
1009  int type_of_element; // ID describing a type of a mesh element
1010  int n_tags; // number of different tags describing an element
1011  int phys_domain; // element's attribute
1012  int elem_domain; // another element's attribute (rarely used)
1013  int n_partitions; // number of partitions where an element takes place
1014 
1015  // number of nodes for each type of Gmsh elements, type is the index of
1016  // the array + 1
1017  int nodes_of_gmsh_element[] =
1018  {
1019  2, // 2-node line.
1020  3, // 3-node triangle.
1021  4, // 4-node quadrangle.
1022  4, // 4-node tetrahedron.
1023  8, // 8-node hexahedron.
1024  6, // 6-node prism.
1025  5, // 5-node pyramid.
1026  3, /* 3-node second order line (2 nodes associated with the
1027  vertices and 1 with the edge). */
1028  6, /* 6-node second order triangle (3 nodes associated with the
1029  vertices and 3 with the edges). */
1030  9, /* 9-node second order quadrangle (4 nodes associated with the
1031  vertices, 4 with the edges and 1 with the face). */
1032  10, /* 10-node second order tetrahedron (4 nodes associated with
1033  the vertices and 6 with the edges). */
1034  27, /* 27-node second order hexahedron (8 nodes associated with the
1035  vertices, 12 with the edges, 6 with the faces and 1 with the
1036  volume). */
1037  18, /* 18-node second order prism (6 nodes associated with the
1038  vertices, 9 with the edges and 3 with the quadrangular
1039  faces). */
1040  14, /* 14-node second order pyramid (5 nodes associated with the
1041  vertices, 8 with the edges and 1 with the quadrangular
1042  face). */
1043  1, // 1-node point.
1044  8, /* 8-node second order quadrangle (4 nodes associated with the
1045  vertices and 4 with the edges). */
1046  20, /* 20-node second order hexahedron (8 nodes associated with the
1047  vertices and 12 with the edges). */
1048  15, /* 15-node second order prism (6 nodes associated with the
1049  vertices and 9 with the edges). */
1050  13, /* 13-node second order pyramid (5 nodes associated with the
1051  vertices and 8 with the edges). */
1052  9, /* 9-node third order incomplete triangle (3 nodes associated
1053  with the vertices, 6 with the edges) */
1054  10, /* 10-node third order triangle (3 nodes associated with the
1055  vertices, 6 with the edges, 1 with the face) */
1056  12, /* 12-node fourth order incomplete triangle (3 nodes associated
1057  with the vertices, 9 with the edges) */
1058  15, /* 15-node fourth order triangle (3 nodes associated with the
1059  vertices, 9 with the edges, 3 with the face) */
1060  15, /* 15-node fifth order incomplete triangle (3 nodes associated
1061  with the vertices, 12 with the edges) */
1062  21, /* 21-node fifth order complete triangle (3 nodes associated
1063  with the vertices, 12 with the edges, 6 with the face) */
1064  4, /* 4-node third order edge (2 nodes associated with the
1065  vertices, 2 internal to the edge) */
1066  5, /* 5-node fourth order edge (2 nodes associated with the
1067  vertices, 3 internal to the edge) */
1068  6, /* 6-node fifth order edge (2 nodes associated with the
1069  vertices, 4 internal to the edge) */
1070  20, /* 20-node third order tetrahedron (4 nodes associated with the
1071  vertices, 12 with the edges, 4 with the faces) */
1072  35, /* 35-node fourth order tetrahedron (4 nodes associated with
1073  the vertices, 18 with the edges, 12 with the faces, and 1
1074  with the volume) */
1075  56, /* 56-node fifth order tetrahedron (4 nodes associated with the
1076  vertices, 24 with the edges, 24 with the faces, and 4 with
1077  the volume) */
1078  -1,-1, /* unsupported tetrahedral types */
1079  -1,-1, /* unsupported polygonal and polyhedral types */
1080  16, /* 16-node third order quadrilateral (4 nodes associated with
1081  the vertices, 8 with the edges, 4 wth the face) */
1082  25, /* 25-node fourth order quadrilateral (4 nodes associated with
1083  the vertices, 12 with the edges, 9 wth the face) */
1084  36, /* 36-node fifth order quadrilateral (4 nodes associated with
1085  the vertices, 16 with the edges, 16 wth the face) */
1086  -1,-1,-1, /* unsupported quadrilateral types */
1087  28, /* 28-node sixth order complete triangle (3 nodes associated
1088  with the vertices, 15 with the edges, 10 with the face) */
1089  36, /* 36-node seventh order complete triangle (3 nodes associated
1090  with the vertices, 18 with the edges, 15 with the face) */
1091  45, /* 45-node eighth order complete triangle (3 nodes associated
1092  with the vertices, 21 with the edges, 21 with the face) */
1093  55, /* 55-node ninth order complete triangle (3 nodes associated
1094  with the vertices, 24 with the edges, 28 with the face) */
1095  66, /* 66-node tenth order complete triangle (3 nodes associated
1096  with the vertices, 27 with the edges, 36 with the face) */
1097  49, /* 49-node sixth order quadrilateral (4 nodes associated with
1098  the vertices, 20 with the edges, 25 wth the face) */
1099  64, /* 64-node seventh order quadrilateral (4 nodes associated with
1100  the vertices, 24 with the edges, 36 wth the face) */
1101  81, /* 81-node eighth order quadrilateral (4 nodes associated with
1102  the vertices, 28 with the edges, 49 wth the face) */
1103  100, /* 100-node ninth order quadrilateral (4 nodes associated with
1104  the vertices, 32 with the edges, 64 wth the face) */
1105  121, /* 121-node tenth order quadrilateral (4 nodes associated with
1106  the vertices, 36 with the edges, 81 wth the face) */
1107  -1,-1,-1,-1,-1, /* unsupported triangular types */
1108  -1,-1,-1,-1,-1, /* unsupported quadrilateral types */
1109  7, /* 7-node sixth order edge (2 nodes associated with the
1110  vertices, 5 internal to the edge) */
1111  8, /* 8-node seventh order edge (2 nodes associated with the
1112  vertices, 6 internal to the edge) */
1113  9, /* 9-node eighth order edge (2 nodes associated with the
1114  vertices, 7 internal to the edge) */
1115  10, /* 10-node ninth order edge (2 nodes associated with the
1116  vertices, 8 internal to the edge) */
1117  11, /* 11-node tenth order edge (2 nodes associated with the
1118  vertices, 9 internal to the edge) */
1119  -1, /* unsupported linear types */
1120  -1,-1,-1, /* unsupported types */
1121  84, /* 84-node sixth order tetrahedron (4 nodes associated with the
1122  vertices, 30 with the edges, 40 with the faces, and 10 with
1123  the volume) */
1124  120, /* 120-node seventh order tetrahedron (4 nodes associated with
1125  the vertices, 36 with the edges, 60 with the faces, and 20
1126  with the volume) */
1127  165, /* 165-node eighth order tetrahedron (4 nodes associated with
1128  the vertices, 42 with the edges, 84 with the faces, and 35
1129  with the volume) */
1130  220, /* 220-node ninth order tetrahedron (4 nodes associated with
1131  the vertices, 48 with the edges, 112 with the faces, and 56
1132  with the volume) */
1133  286, /* 286-node tenth order tetrahedron (4 nodes associated with
1134  the vertices, 54 with the edges, 144 with the faces, and 84
1135  with the volume) */
1136  -1,-1,-1, /* undefined types */
1137  -1,-1,-1,-1,-1, /* unsupported tetrahedral types */
1138  -1,-1,-1,-1,-1,-1, /* unsupported types */
1139  40, /* 40-node third order prism (6 nodes associated with the
1140  vertices, 18 with the edges, 14 with the faces, and 2 with
1141  the volume) */
1142  75, /* 75-node fourth order prism (6 nodes associated with the
1143  vertices, 27 with the edges, 33 with the faces, and 9 with
1144  the volume) */
1145  64, /* 64-node third order hexahedron (8 nodes associated with the
1146  vertices, 24 with the edges, 24 with the faces and 8 with
1147  the volume).*/
1148  125, /* 125-node fourth order hexahedron (8 nodes associated with
1149  the vertices, 36 with the edges, 54 with the faces and 27
1150  with the volume).*/
1151  216, /* 216-node fifth order hexahedron (8 nodes associated with the
1152  vertices, 48 with the edges, 96 with the faces and 64 with
1153  the volume).*/
1154  343, /* 343-node sixth order hexahedron (8 nodes associated with the
1155  vertices, 60 with the edges, 150 with the faces and 125 with
1156  the volume).*/
1157  512, /* 512-node seventh order hexahedron (8 nodes associated with
1158  the vertices, 72 with the edges, 216 with the faces and 216
1159  with the volume).*/
1160  729, /* 729-node eighth order hexahedron (8 nodes associated with
1161  the vertices, 84 with the edges, 294 with the faces and 343
1162  with the volume).*/
1163  1000,/* 1000-node ninth order hexahedron (8 nodes associated with
1164  the vertices, 96 with the edges, 384 with the faces and 512
1165  with the volume).*/
1166  -1,-1,-1,-1,-1,-1,-1, /* unsupported hexahedron types */
1167  126, /* 126-node fifth order prism (6 nodes associated with the
1168  vertices, 36 with the edges, 60 with the faces, and 24 with
1169  the volume) */
1170  196, /* 196-node sixth order prism (6 nodes associated with the
1171  vertices, 45 with the edges, 95 with the faces, and 50 with
1172  the volume) */
1173  288, /* 288-node seventh order prism (6 nodes associated with the
1174  vertices, 54 with the edges, 138 with the faces, and 90 with
1175  the volume) */
1176  405, /* 405-node eighth order prism (6 nodes associated with the
1177  vertices, 63 with the edges, 189 with the faces, and 147
1178  with the volume) */
1179  550, /* 550-node ninth order prism (6 nodes associated with the
1180  vertices, 72 with the edges, 248 with the faces, and 224
1181  with the volume) */
1182  -1,-1,-1,-1,-1,-1,-1, /* unsupported prism types */
1183  30, /* 30-node third order pyramid (5 nodes associated with the
1184  vertices, 16 with the edges and 8 with the faces, and 1 with
1185  the volume). */
1186  55, /* 55-node fourth order pyramid (5 nodes associated with the
1187  vertices, 24 with the edges and 21 with the faces, and 5
1188  with the volume). */
1189  91, /* 91-node fifth order pyramid (5 nodes associated with the
1190  vertices, 32 with the edges and 40 with the faces, and 14
1191  with the volume). */
1192  140, /* 140-node sixth order pyramid (5 nodes associated with the
1193  vertices, 40 with the edges and 65 with the faces, and 30
1194  with the volume). */
1195  204, /* 204-node seventh order pyramid (5 nodes associated with the
1196  vertices, 48 with the edges and 96 with the faces, and 55
1197  with the volume). */
1198  285, /* 285-node eighth order pyramid (5 nodes associated with the
1199  vertices, 56 with the edges and 133 with the faces, and 91
1200  with the volume). */
1201  385 /* 385-node ninth order pyramid (5 nodes associated with the
1202  vertices, 64 with the edges and 176 with the faces, and 140
1203  with the volume). */
1204  };
1205 
1206  /** The following mappings convert the Gmsh node orderings for high
1207  order elements to MFEM's L2 degree of freedom ordering. To support
1208  more options examine Gmsh's ordering and read off the indices in
1209  MFEM's order. For example 2nd order Gmsh quadrilaterals use the
1210  following ordering:
1211 
1212  3--6--2
1213  | | |
1214  7 8 5
1215  | | |
1216  0--4--1
1217 
1218  (from https://gmsh.info/doc/texinfo/gmsh.html#Node-ordering)
1219 
1220  Whereas MFEM uses a tensor product ordering with the horizontal
1221  axis cycling fastest so we would read off:
1222 
1223  0 4 1 7 8 5 3 6 2
1224 
1225  This corresponds to the quad9 mapping below.
1226  */
1227  int lin3[] = {0,2,1}; // 2nd order segment
1228  int lin4[] = {0,2,3,1}; // 3rd order segment
1229  int tri6[] = {0,3,1,5,4,2}; // 2nd order triangle
1230  int tri10[] = {0,3,4,1,8,9,5,7,6,2}; // 3rd order triangle
1231  int quad9[] = {0,4,1,7,8,5,3,6,2}; // 2nd order quadrilateral
1232  int quad16[] = {0,4,5,1,11,12,13,6, // 3rd order quadrilateral
1233  10,15,14,7,3,9,8,2
1234  };
1235  int tet10[] {0,4,1,6,5,2,7,9,8,3}; // 2nd order tetrahedron
1236  int tet20[] = {0,4,5,1,9,16,6,8,7,2, // 3rd order tetrahedron
1237  11,17,15,18,19,13,10,14,12,3
1238  };
1239  int hex27[] {0,8,1,9,20,11,3,13,2, // 2nd order hexahedron
1240  10,21,12,22,26,23,15,24,14,
1241  4,16,5,17,25,18,7,19,6
1242  };
1243  int hex64[] {0,8,9,1,10,32,35,14, // 3rd order hexahedron
1244  11,33,34,15,3,19,18,2,
1245  12,36,37,16,40,56,57,44,
1246  43,59,58,45,22,49,48,20,
1247  13,39,38,17,41,60,61,47,
1248  42,63,62,46,23,50,51,21,
1249  4,24,25,5,26,52,53,28,
1250  27,55,54,29,7,31,30,6
1251  };
1252 
1253  int wdg18[] = {0,6,1,7,9,2,8,15,10, // 2nd order wedge/prism
1254  16,17,11,3,12,4,13,14,5
1255  };
1256  int wdg40[] = {0,6,7,1,8,24,12,9,13,2, // 3rd order wedge/prism
1257  10,26,27,14,30,38,34,33,35,16,
1258  11,29,28,15,31,39,37,32,36,17,
1259  3,18,19,4,20,25,22,21,23,5
1260  };
1261 
1262  int pyr14[] = {0,5,1,6,13,8,3, // 2nd order pyramid
1263  10,2,7,9,12,11,4
1264  };
1265  int pyr30[] = {0,5,6,1,7,25,28,11,8,26, // 3rd order pyramid
1266  27,12,3,16,15,2,9,21,13,22,
1267  29,23,19,24,17,10,14,20,18,4
1268  };
1269 
1270  vector<Element*> elements_0D, elements_1D, elements_2D, elements_3D;
1271  elements_0D.reserve(num_of_all_elements);
1272  elements_1D.reserve(num_of_all_elements);
1273  elements_2D.reserve(num_of_all_elements);
1274  elements_3D.reserve(num_of_all_elements);
1275 
1276  // Temporary storage for high order vertices, if present
1277  vector<Array<int>*> ho_verts_1D, ho_verts_2D, ho_verts_3D;
1278  ho_verts_1D.reserve(num_of_all_elements);
1279  ho_verts_2D.reserve(num_of_all_elements);
1280  ho_verts_3D.reserve(num_of_all_elements);
1281 
1282  // Temporary storage for order of elements
1283  vector<int> ho_el_order_1D, ho_el_order_2D, ho_el_order_3D;
1284  ho_el_order_1D.reserve(num_of_all_elements);
1285  ho_el_order_2D.reserve(num_of_all_elements);
1286  ho_el_order_3D.reserve(num_of_all_elements);
1287 
1288  // Vertex order mappings
1289  Array<int*> ho_lin(11); ho_lin = NULL;
1290  Array<int*> ho_tri(11); ho_tri = NULL;
1291  Array<int*> ho_sqr(11); ho_sqr = NULL;
1292  Array<int*> ho_tet(11); ho_tet = NULL;
1293  Array<int*> ho_hex(10); ho_hex = NULL;
1294  Array<int*> ho_wdg(10); ho_wdg = NULL;
1295  Array<int*> ho_pyr(10); ho_pyr = NULL;
1296 
1297  // Use predefined arrays at lowest orders (for efficiency)
1298  ho_lin[2] = lin3; ho_lin[3] = lin4;
1299  ho_tri[2] = tri6; ho_tri[3] = tri10;
1300  ho_sqr[2] = quad9; ho_sqr[3] = quad16;
1301  ho_tet[2] = tet10; ho_tet[3] = tet20;
1302  ho_hex[2] = hex27; ho_hex[3] = hex64;
1303  ho_wdg[2] = wdg18; ho_wdg[3] = wdg40;
1304  ho_pyr[2] = pyr14; ho_pyr[3] = pyr30;
1305 
1306  if (binary)
1307  {
1308  int n_elem_part = 0; // partial sum of elements that are read
1309  const int header_size = 3;
1310  // header consists of 3 numbers: type of the element, number of
1311  // elements of this type, and number of tags
1312  int header[header_size];
1313  int n_elem_one_type; // number of elements of a specific type
1314 
1315  while (n_elem_part < num_of_all_elements)
1316  {
1317  input.read(reinterpret_cast<char*>(header),
1318  header_size*sizeof(int));
1319  type_of_element = header[0];
1320  n_elem_one_type = header[1];
1321  n_tags = header[2];
1322 
1323  n_elem_part += n_elem_one_type;
1324 
1325  const int n_elem_nodes = nodes_of_gmsh_element[type_of_element-1];
1326  vector<int> data(1+n_tags+n_elem_nodes);
1327  for (int el = 0; el < n_elem_one_type; ++el)
1328  {
1329  input.read(reinterpret_cast<char*>(&data[0]),
1330  data.size()*sizeof(int));
1331  int dd = 0; // index for data array
1332  serial_number = data[dd++];
1333  // physical domain - the most important value (to distinguish
1334  // materials with different properties)
1335  phys_domain = (n_tags > 0) ? data[dd++] : 1;
1336  // elementary domain - to distinguish different geometrical
1337  // domains (typically, it's used rarely)
1338  elem_domain = (n_tags > 1) ? data[dd++] : 0;
1339  // the number of tags is bigger than 2 if there are some
1340  // partitions (domain decompositions)
1341  n_partitions = (n_tags > 2) ? data[dd++] : 0;
1342  // we currently just skip the partitions if they exist, and go
1343  // directly to vertices describing the mesh element
1344  vector<int> vert_indices(n_elem_nodes);
1345  for (int vi = 0; vi < n_elem_nodes; ++vi)
1346  {
1347  map<int, int>::const_iterator it =
1348  vertices_map.find(data[1+n_tags+vi]);
1349  if (it == vertices_map.end())
1350  {
1351  MFEM_ABORT("Gmsh file : vertex index doesn't exist");
1352  }
1353  vert_indices[vi] = it->second;
1354  }
1355 
1356  // non-positive attributes are not allowed in MFEM
1357  if (phys_domain <= 0)
1358  {
1359  MFEM_ABORT("Non-positive element attribute in Gmsh mesh!");
1360  }
1361 
1362  // initialize the mesh element
1363  int el_order = 11;
1364  switch (type_of_element)
1365  {
1366  case 1: // 2-node line
1367  case 8: // 3-node line (2nd order)
1368  case 26: // 4-node line (3rd order)
1369  case 27: // 5-node line (4th order)
1370  case 28: // 6-node line (5th order)
1371  case 62: // 7-node line (6th order)
1372  case 63: // 8-node line (7th order)
1373  case 64: // 9-node line (8th order)
1374  case 65: // 10-node line (9th order)
1375  case 66: // 11-node line (10th order)
1376  {
1377  elements_1D.push_back(
1378  new Segment(&vert_indices[0], phys_domain));
1379  if (type_of_element != 1)
1380  {
1381  el_order = n_elem_nodes - 1;
1382  Array<int> * hov = new Array<int>;
1383  hov->Append(&vert_indices[0], n_elem_nodes);
1384  ho_verts_1D.push_back(hov);
1385  ho_el_order_1D.push_back(el_order);
1386  }
1387  break;
1388  }
1389  case 2: el_order--; // 3-node triangle
1390  case 9: el_order--; // 6-node triangle (2nd order)
1391  case 21: el_order--; // 10-node triangle (3rd order)
1392  case 23: el_order--; // 15-node triangle (4th order)
1393  case 25: el_order--; // 21-node triangle (5th order)
1394  case 42: el_order--; // 28-node triangle (6th order)
1395  case 43: el_order--; // 36-node triangle (7th order)
1396  case 44: el_order--; // 45-node triangle (8th order)
1397  case 45: el_order--; // 55-node triangle (9th order)
1398  case 46: el_order--; // 66-node triangle (10th order)
1399  {
1400  elements_2D.push_back(
1401  new Triangle(&vert_indices[0], phys_domain));
1402  if (el_order > 1)
1403  {
1404  Array<int> * hov = new Array<int>;
1405  hov->Append(&vert_indices[0], n_elem_nodes);
1406  ho_verts_2D.push_back(hov);
1407  ho_el_order_2D.push_back(el_order);
1408  }
1409  break;
1410  }
1411  case 3: el_order--; // 4-node quadrangle
1412  case 10: el_order--; // 9-node quadrangle (2nd order)
1413  case 36: el_order--; // 16-node quadrangle (3rd order)
1414  case 37: el_order--; // 25-node quadrangle (4th order)
1415  case 38: el_order--; // 36-node quadrangle (5th order)
1416  case 47: el_order--; // 49-node quadrangle (6th order)
1417  case 48: el_order--; // 64-node quadrangle (7th order)
1418  case 49: el_order--; // 81-node quadrangle (8th order)
1419  case 50: el_order--; // 100-node quadrangle (9th order)
1420  case 51: el_order--; // 121-node quadrangle (10th order)
1421  {
1422  elements_2D.push_back(
1423  new Quadrilateral(&vert_indices[0], phys_domain));
1424  if (el_order > 1)
1425  {
1426  Array<int> * hov = new Array<int>;
1427  hov->Append(&vert_indices[0], n_elem_nodes);
1428  ho_verts_2D.push_back(hov);
1429  ho_el_order_2D.push_back(el_order);
1430  }
1431  break;
1432  }
1433  case 4: el_order--; // 4-node tetrahedron
1434  case 11: el_order--; // 10-node tetrahedron (2nd order)
1435  case 29: el_order--; // 20-node tetrahedron (3rd order)
1436  case 30: el_order--; // 35-node tetrahedron (4th order)
1437  case 31: el_order--; // 56-node tetrahedron (5th order)
1438  case 71: el_order--; // 84-node tetrahedron (6th order)
1439  case 72: el_order--; // 120-node tetrahedron (7th order)
1440  case 73: el_order--; // 165-node tetrahedron (8th order)
1441  case 74: el_order--; // 220-node tetrahedron (9th order)
1442  case 75: el_order--; // 286-node tetrahedron (10th order)
1443  {
1444 #ifdef MFEM_USE_MEMALLOC
1445  elements_3D.push_back(TetMemory.Alloc());
1446  elements_3D.back()->SetVertices(&vert_indices[0]);
1447  elements_3D.back()->SetAttribute(phys_domain);
1448 #else
1449  elements_3D.push_back(
1450  new Tetrahedron(&vert_indices[0], phys_domain));
1451 #endif
1452  if (el_order > 1)
1453  {
1454  Array<int> * hov = new Array<int>;
1455  hov->Append(&vert_indices[0], n_elem_nodes);
1456  ho_verts_3D.push_back(hov);
1457  ho_el_order_3D.push_back(el_order);
1458  }
1459  break;
1460  }
1461  case 5: el_order--; // 8-node hexahedron
1462  case 12: el_order--; // 27-node hexahedron (2nd order)
1463  case 92: el_order--; // 64-node hexahedron (3rd order)
1464  case 93: el_order--; // 125-node hexahedron (4th order)
1465  case 94: el_order--; // 216-node hexahedron (5th order)
1466  case 95: el_order--; // 343-node hexahedron (6th order)
1467  case 96: el_order--; // 512-node hexahedron (7th order)
1468  case 97: el_order--; // 729-node hexahedron (8th order)
1469  case 98: el_order--; // 1000-node hexahedron (9th order)
1470  {
1471  el_order--; // Gmsh does not define an order 10 hex
1472  elements_3D.push_back(
1473  new Hexahedron(&vert_indices[0], phys_domain));
1474  if (el_order > 1)
1475  {
1476  Array<int> * hov = new Array<int>;
1477  hov->Append(&vert_indices[0], n_elem_nodes);
1478  ho_verts_3D.push_back(hov);
1479  ho_el_order_3D.push_back(el_order);
1480  }
1481  break;
1482  }
1483  case 6: el_order--; // 6-node wedge
1484  case 13: el_order--; // 18-node wedge (2nd order)
1485  case 90: el_order--; // 40-node wedge (3rd order)
1486  case 91: el_order--; // 75-node wedge (4th order)
1487  case 106: el_order--; // 126-node wedge (5th order)
1488  case 107: el_order--; // 196-node wedge (6th order)
1489  case 108: el_order--; // 288-node wedge (7th order)
1490  case 109: el_order--; // 405-node wedge (8th order)
1491  case 110: el_order--; // 550-node wedge (9th order)
1492  {
1493  el_order--; // Gmsh does not define an order 10 wedge
1494  elements_3D.push_back(
1495  new Wedge(&vert_indices[0], phys_domain));
1496  if (el_order > 1)
1497  {
1498  Array<int> * hov = new Array<int>;
1499  hov->Append(&vert_indices[0], n_elem_nodes);
1500  ho_verts_3D.push_back(hov);
1501  ho_el_order_3D.push_back(el_order);
1502  }
1503  break;
1504  }
1505  /*
1506  // MFEM does not support pyramids yet
1507  case 7: el_order--; // 5-node pyramid
1508  case 14: el_order--; // 14-node pyramid (2nd order)
1509  case 118: el_order--; // 30-node pyramid (3rd order)
1510  case 119: el_order--; // 55-node pyramid (4th order)
1511  case 120: el_order--; // 91-node pyramid (5th order)
1512  case 121: el_order--; // 140-node pyramid (6th order)
1513  case 122: el_order--; // 204-node pyramid (7th order)
1514  case 123: el_order--; // 285-node pyramid (8th order)
1515  case 124: el_order--; // 385-node pyramid (9th order)
1516  {
1517  el_order--; // Gmsh does not define an order 10 pyr
1518  elements_3D.push_back(
1519  new Pyramid(&vert_indices[0], phys_domain));
1520  if (el_order > 1)
1521  {
1522  Array<int> * hov = new Array<int>;
1523  hov->Append(&vert_indices[0], n_elem_nodes);
1524  ho_verts_3D.push_back(hov);
1525  ho_el_order_3D.push_back(el_order);
1526  }
1527  break;
1528  }
1529  */
1530  case 15: // 1-node point
1531  {
1532  elements_0D.push_back(
1533  new Point(&vert_indices[0], phys_domain));
1534  break;
1535  }
1536  default: // any other element
1537  MFEM_WARNING("Unsupported Gmsh element type.");
1538  break;
1539 
1540  } // switch (type_of_element)
1541  } // el (elements of one type)
1542  } // all elements
1543  } // if binary
1544  else // ASCII
1545  {
1546  for (int el = 0; el < num_of_all_elements; ++el)
1547  {
1548  input >> serial_number >> type_of_element >> n_tags;
1549  vector<int> data(n_tags);
1550  for (int i = 0; i < n_tags; ++i) { input >> data[i]; }
1551  // physical domain - the most important value (to distinguish
1552  // materials with different properties)
1553  phys_domain = (n_tags > 0) ? data[0] : 1;
1554  // elementary domain - to distinguish different geometrical
1555  // domains (typically, it's used rarely)
1556  elem_domain = (n_tags > 1) ? data[1] : 0;
1557  // the number of tags is bigger than 2 if there are some
1558  // partitions (domain decompositions)
1559  n_partitions = (n_tags > 2) ? data[2] : 0;
1560  // we currently just skip the partitions if they exist, and go
1561  // directly to vertices describing the mesh element
1562  const int n_elem_nodes = nodes_of_gmsh_element[type_of_element-1];
1563  vector<int> vert_indices(n_elem_nodes);
1564  int index;
1565  for (int vi = 0; vi < n_elem_nodes; ++vi)
1566  {
1567  input >> index;
1568  map<int, int>::const_iterator it = vertices_map.find(index);
1569  if (it == vertices_map.end())
1570  {
1571  MFEM_ABORT("Gmsh file : vertex index doesn't exist");
1572  }
1573  vert_indices[vi] = it->second;
1574  }
1575 
1576  // non-positive attributes are not allowed in MFEM
1577  if (phys_domain <= 0)
1578  {
1579  MFEM_ABORT("Non-positive element attribute in Gmsh mesh!");
1580  }
1581 
1582  // initialize the mesh element
1583  int el_order = 11;
1584  switch (type_of_element)
1585  {
1586  case 1: // 2-node line
1587  case 8: // 3-node line (2nd order)
1588  case 26: // 4-node line (3rd order)
1589  case 27: // 5-node line (4th order)
1590  case 28: // 6-node line (5th order)
1591  case 62: // 7-node line (6th order)
1592  case 63: // 8-node line (7th order)
1593  case 64: // 9-node line (8th order)
1594  case 65: // 10-node line (9th order)
1595  case 66: // 11-node line (10th order)
1596  {
1597  elements_1D.push_back(
1598  new Segment(&vert_indices[0], phys_domain));
1599  if (type_of_element != 1)
1600  {
1601  Array<int> * hov = new Array<int>;
1602  hov->Append(&vert_indices[0], n_elem_nodes);
1603  ho_verts_1D.push_back(hov);
1604  el_order = n_elem_nodes - 1;
1605  ho_el_order_1D.push_back(el_order);
1606  }
1607  break;
1608  }
1609  case 2: el_order--; // 3-node triangle
1610  case 9: el_order--; // 6-node triangle (2nd order)
1611  case 21: el_order--; // 10-node triangle (3rd order)
1612  case 23: el_order--; // 15-node triangle (4th order)
1613  case 25: el_order--; // 21-node triangle (5th order)
1614  case 42: el_order--; // 28-node triangle (6th order)
1615  case 43: el_order--; // 36-node triangle (7th order)
1616  case 44: el_order--; // 45-node triangle (8th order)
1617  case 45: el_order--; // 55-node triangle (9th order)
1618  case 46: el_order--; // 66-node triangle (10th order)
1619  {
1620  elements_2D.push_back(
1621  new Triangle(&vert_indices[0], phys_domain));
1622  if (el_order > 1)
1623  {
1624  Array<int> * hov = new Array<int>;
1625  hov->Append(&vert_indices[0], n_elem_nodes);
1626  ho_verts_2D.push_back(hov);
1627  ho_el_order_2D.push_back(el_order);
1628  }
1629  break;
1630  }
1631  case 3: el_order--; // 4-node quadrangle
1632  case 10: el_order--; // 9-node quadrangle (2nd order)
1633  case 36: el_order--; // 16-node quadrangle (3rd order)
1634  case 37: el_order--; // 25-node quadrangle (4th order)
1635  case 38: el_order--; // 36-node quadrangle (5th order)
1636  case 47: el_order--; // 49-node quadrangle (6th order)
1637  case 48: el_order--; // 64-node quadrangle (7th order)
1638  case 49: el_order--; // 81-node quadrangle (8th order)
1639  case 50: el_order--; // 100-node quadrangle (9th order)
1640  case 51: el_order--; // 121-node quadrangle (10th order)
1641  {
1642  elements_2D.push_back(
1643  new Quadrilateral(&vert_indices[0], phys_domain));
1644  if (el_order > 1)
1645  {
1646  Array<int> * hov = new Array<int>;
1647  hov->Append(&vert_indices[0], n_elem_nodes);
1648  ho_verts_2D.push_back(hov);
1649  ho_el_order_2D.push_back(el_order);
1650  }
1651  break;
1652  }
1653  case 4: el_order--; // 4-node tetrahedron
1654  case 11: el_order--; // 10-node tetrahedron (2nd order)
1655  case 29: el_order--; // 20-node tetrahedron (3rd order)
1656  case 30: el_order--; // 35-node tetrahedron (4th order)
1657  case 31: el_order--; // 56-node tetrahedron (5th order)
1658  case 71: el_order--; // 84-node tetrahedron (6th order)
1659  case 72: el_order--; // 120-node tetrahedron (7th order)
1660  case 73: el_order--; // 165-node tetrahedron (8th order)
1661  case 74: el_order--; // 220-node tetrahedron (9th order)
1662  case 75: el_order--; // 286-node tetrahedron (10th order)
1663  {
1664 #ifdef MFEM_USE_MEMALLOC
1665  elements_3D.push_back(TetMemory.Alloc());
1666  elements_3D.back()->SetVertices(&vert_indices[0]);
1667  elements_3D.back()->SetAttribute(phys_domain);
1668 #else
1669  elements_3D.push_back(
1670  new Tetrahedron(&vert_indices[0], phys_domain));
1671 #endif
1672  if (el_order > 1)
1673  {
1674  Array<int> * hov = new Array<int>;
1675  hov->Append(&vert_indices[0], n_elem_nodes);
1676  ho_verts_3D.push_back(hov);
1677  ho_el_order_3D.push_back(el_order);
1678  }
1679  break;
1680  }
1681  case 5: el_order--; // 8-node hexahedron
1682  case 12: el_order--; // 27-node hexahedron (2nd order)
1683  case 92: el_order--; // 64-node hexahedron (3rd order)
1684  case 93: el_order--; // 125-node hexahedron (4th order)
1685  case 94: el_order--; // 216-node hexahedron (5th order)
1686  case 95: el_order--; // 343-node hexahedron (6th order)
1687  case 96: el_order--; // 512-node hexahedron (7th order)
1688  case 97: el_order--; // 729-node hexahedron (8th order)
1689  case 98: el_order--; // 1000-node hexahedron (9th order)
1690  {
1691  el_order--;
1692  elements_3D.push_back(
1693  new Hexahedron(&vert_indices[0], phys_domain));
1694  if (el_order > 1)
1695  {
1696  Array<int> * hov = new Array<int>;
1697  hov->Append(&vert_indices[0], n_elem_nodes);
1698  ho_verts_3D.push_back(hov);
1699  ho_el_order_3D.push_back(el_order);
1700  }
1701  break;
1702  }
1703  case 6: el_order--; // 6-node wedge
1704  case 13: el_order--; // 18-node wedge (2nd order)
1705  case 90: el_order--; // 40-node wedge (3rd order)
1706  case 91: el_order--; // 75-node wedge (4th order)
1707  case 106: el_order--; // 126-node wedge (5th order)
1708  case 107: el_order--; // 196-node wedge (6th order)
1709  case 108: el_order--; // 288-node wedge (7th order)
1710  case 109: el_order--; // 405-node wedge (8th order)
1711  case 110: el_order--; // 550-node wedge (9th order)
1712  {
1713  el_order--;
1714  elements_3D.push_back(
1715  new Wedge(&vert_indices[0], phys_domain));
1716  if (el_order > 1)
1717  {
1718  Array<int> * hov = new Array<int>;
1719  hov->Append(&vert_indices[0], n_elem_nodes);
1720  ho_verts_3D.push_back(hov);
1721  ho_el_order_3D.push_back(el_order);
1722  }
1723  break;
1724  }
1725  /*
1726  // MFEM does not support pyramids yet
1727  case 7: el_order--; // 5-node pyramid
1728  case 14: el_order--; // 14-node pyramid (2nd order)
1729  case 118: el_order--; // 30-node pyramid (3rd order)
1730  case 119: el_order--; // 55-node pyramid (4th order)
1731  case 120: el_order--; // 91-node pyramid (5th order)
1732  case 121: el_order--; // 140-node pyramid (6th order)
1733  case 122: el_order--; // 204-node pyramid (7th order)
1734  case 123: el_order--; // 285-node pyramid (8th order)
1735  case 124: el_order--; // 385-node pyramid (9th order)
1736  {
1737  el_order--;
1738  elements_3D.push_back(
1739  new Pyramid(&vert_indices[0], phys_domain));
1740  if (el_order > 1)
1741  {
1742  Array<int> * hov = new Array<int>;
1743  hov->Append(&vert_indices[0], n_elem_nodes);
1744  ho_verts_3D.push_back(hov);
1745  ho_el_order_3D.push_back(el_order);
1746  }
1747  break;
1748  }
1749  */
1750  case 15: // 1-node point
1751  {
1752  elements_0D.push_back(
1753  new Point(&vert_indices[0], phys_domain));
1754  break;
1755  }
1756  default: // any other element
1757  MFEM_WARNING("Unsupported Gmsh element type.");
1758  break;
1759 
1760  } // switch (type_of_element)
1761  } // el (all elements)
1762  } // if ASCII
1763 
1764  if (!elements_3D.empty())
1765  {
1766  Dim = 3;
1767  NumOfElements = elements_3D.size();
1768  elements.SetSize(NumOfElements);
1769  for (int el = 0; el < NumOfElements; ++el)
1770  {
1771  elements[el] = elements_3D[el];
1772  }
1773  NumOfBdrElements = elements_2D.size();
1774  boundary.SetSize(NumOfBdrElements);
1775  for (int el = 0; el < NumOfBdrElements; ++el)
1776  {
1777  boundary[el] = elements_2D[el];
1778  }
1779  for (size_t el = 0; el < ho_el_order_3D.size(); el++)
1780  {
1781  mesh_order = max(mesh_order, ho_el_order_3D[el]);
1782  }
1783  // discard other elements
1784  for (size_t el = 0; el < elements_1D.size(); ++el)
1785  {
1786  delete elements_1D[el];
1787  }
1788  for (size_t el = 0; el < elements_0D.size(); ++el)
1789  {
1790  delete elements_0D[el];
1791  }
1792  }
1793  else if (!elements_2D.empty())
1794  {
1795  Dim = 2;
1796  NumOfElements = elements_2D.size();
1797  elements.SetSize(NumOfElements);
1798  for (int el = 0; el < NumOfElements; ++el)
1799  {
1800  elements[el] = elements_2D[el];
1801  }
1802  NumOfBdrElements = elements_1D.size();
1803  boundary.SetSize(NumOfBdrElements);
1804  for (int el = 0; el < NumOfBdrElements; ++el)
1805  {
1806  boundary[el] = elements_1D[el];
1807  }
1808  for (size_t el = 0; el < ho_el_order_2D.size(); el++)
1809  {
1810  mesh_order = max(mesh_order, ho_el_order_2D[el]);
1811  }
1812  // discard other elements
1813  for (size_t el = 0; el < elements_0D.size(); ++el)
1814  {
1815  delete elements_0D[el];
1816  }
1817  }
1818  else if (!elements_1D.empty())
1819  {
1820  Dim = 1;
1821  NumOfElements = elements_1D.size();
1822  elements.SetSize(NumOfElements);
1823  for (int el = 0; el < NumOfElements; ++el)
1824  {
1825  elements[el] = elements_1D[el];
1826  }
1827  NumOfBdrElements = elements_0D.size();
1828  boundary.SetSize(NumOfBdrElements);
1829  for (int el = 0; el < NumOfBdrElements; ++el)
1830  {
1831  boundary[el] = elements_0D[el];
1832  }
1833  for (size_t el = 0; el < ho_el_order_1D.size(); el++)
1834  {
1835  mesh_order = max(mesh_order, ho_el_order_1D[el]);
1836  }
1837  }
1838  else
1839  {
1840  MFEM_ABORT("Gmsh file : no elements found");
1841  return;
1842  }
1843 
1844  if (mesh_order > 1)
1845  {
1846  curved = 1;
1847  read_gf = 0;
1848 
1849  // Construct GridFunction for uniformly spaced high order coords
1851  FiniteElementSpace* nfes;
1852  nfec = new L2_FECollection(mesh_order, Dim,
1853  BasisType::ClosedUniform);
1854  nfes = new FiniteElementSpace(this, nfec, spaceDim,
1855  Ordering::byVDIM);
1856  Nodes_gf.SetSpace(nfes);
1857  Nodes_gf.MakeOwner(nfec);
1858 
1859  int o = 0;
1860  int el_order = 1;
1861  for (int el = 0; el < NumOfElements; el++)
1862  {
1863  const int * vm = NULL;
1864  Array<int> * ho_verts = NULL;
1865  switch (GetElementType(el))
1866  {
1867  case Element::SEGMENT:
1868  ho_verts = ho_verts_1D[el];
1869  el_order = ho_el_order_1D[el];
1870  if (!ho_lin[el_order])
1871  {
1872  ho_lin[el_order] = new int[ho_verts->Size()];
1873  GmshHOSegmentMapping(el_order, ho_lin[el_order]);
1874  }
1875  vm = ho_lin[el_order];
1876  break;
1877  case Element::TRIANGLE:
1878  ho_verts = ho_verts_2D[el];
1879  el_order = ho_el_order_2D[el];
1880  if (!ho_tri[el_order])
1881  {
1882  ho_tri[el_order] = new int[ho_verts->Size()];
1883  GmshHOTriangleMapping(el_order, ho_tri[el_order]);
1884  }
1885  vm = ho_tri[el_order];
1886  break;
1887  case Element::QUADRILATERAL:
1888  ho_verts = ho_verts_2D[el];
1889  el_order = ho_el_order_2D[el];
1890  if (!ho_sqr[el_order])
1891  {
1892  ho_sqr[el_order] = new int[ho_verts->Size()];
1893  GmshHOQuadrilateralMapping(el_order, ho_sqr[el_order]);
1894  }
1895  vm = ho_sqr[el_order];
1896  break;
1897  case Element::TETRAHEDRON:
1898  ho_verts = ho_verts_3D[el];
1899  el_order = ho_el_order_3D[el];
1900  if (!ho_tet[el_order])
1901  {
1902  ho_tet[el_order] = new int[ho_verts->Size()];
1903  GmshHOTetrahedronMapping(el_order, ho_tet[el_order]);
1904  }
1905  vm = ho_tet[el_order];
1906  break;
1907  case Element::HEXAHEDRON:
1908  ho_verts = ho_verts_3D[el];
1909  el_order = ho_el_order_3D[el];
1910  if (!ho_hex[el_order])
1911  {
1912  ho_hex[el_order] = new int[ho_verts->Size()];
1913  GmshHOHexahedronMapping(el_order, ho_hex[el_order]);
1914  }
1915  vm = ho_hex[el_order];
1916  break;
1917  case Element::WEDGE:
1918  ho_verts = ho_verts_3D[el];
1919  el_order = ho_el_order_3D[el];
1920  if (!ho_wdg[el_order])
1921  {
1922  ho_wdg[el_order] = new int[ho_verts->Size()];
1923  GmshHOWedgeMapping(el_order, ho_wdg[el_order]);
1924  }
1925  vm = ho_wdg[el_order];
1926  break;
1927  // case Element::PYRAMID:
1928  // ho_verts = ho_verts_3D[el];
1929  // el_order = ho_el_order_3D[el];
1930  // if (ho_pyr[el_order])
1931  // {
1932  // ho_pyr[el_order] = new int[ho_verts->Size()];
1933  // GmshHOPyramidMapping(el_order, ho_pyr[el_order]);
1934  // }
1935  // vm = ho_pyr[el_order];
1936  // break;
1937  default: // Any other element type
1938  MFEM_WARNING("Unsupported Gmsh element type.");
1939  break;
1940  }
1941  int nv = (ho_verts) ? ho_verts->Size() : 0;
1942 
1943  for (int v = 0; v<nv; v++)
1944  {
1945  double * c = GetVertex((*ho_verts)[vm[v]]);
1946  for (int d=0; d<spaceDim; d++)
1947  {
1948  Nodes_gf(spaceDim * (o + v) + d) = c[d];
1949  }
1950  }
1951  o += nv;
1952  }
1953  }
1954 
1955  // Delete any high order element to vertex connectivity
1956  for (size_t el=0; el<ho_verts_1D.size(); el++)
1957  {
1958  delete ho_verts_1D[el];
1959  }
1960  for (size_t el=0; el<ho_verts_2D.size(); el++)
1961  {
1962  delete ho_verts_2D[el];
1963  }
1964  for (size_t el=0; el<ho_verts_3D.size(); el++)
1965  {
1966  delete ho_verts_3D[el];
1967  }
1968 
1969  // Delete dynamically allocated high vertex order mappings
1970  for (int ord=4; ord<ho_lin.Size(); ord++)
1971  {
1972  if (ho_lin[ord] != NULL) { delete [] ho_lin[ord]; }
1973  }
1974  for (int ord=4; ord<ho_tri.Size(); ord++)
1975  {
1976  if (ho_tri[ord] != NULL) { delete [] ho_tri[ord]; }
1977  }
1978  for (int ord=4; ord<ho_sqr.Size(); ord++)
1979  {
1980  if (ho_sqr[ord] != NULL) { delete [] ho_sqr[ord]; }
1981  }
1982  for (int ord=4; ord<ho_tet.Size(); ord++)
1983  {
1984  if (ho_tet[ord] != NULL) { delete [] ho_tet[ord]; }
1985  }
1986  for (int ord=4; ord<ho_hex.Size(); ord++)
1987  {
1988  if (ho_hex[ord] != NULL) { delete [] ho_hex[ord]; }
1989  }
1990  for (int ord=4; ord<ho_wdg.Size(); ord++)
1991  {
1992  if (ho_wdg[ord] != NULL) { delete [] ho_wdg[ord]; }
1993  }
1994  for (int ord=4; ord<ho_pyr.Size(); ord++)
1995  {
1996  if (ho_pyr[ord] != NULL) { delete [] ho_pyr[ord]; }
1997  }
1998 
1999  MFEM_CONTRACT_VAR(n_partitions);
2000  MFEM_CONTRACT_VAR(elem_domain);
2001 
2002  } // section '$Elements'
2003  else if (buff == "$Periodic") // Reading master/slave node pairs
2004  {
2005  curved = 1;
2006  read_gf = 0;
2007  periodic = true;
2008 
2009  Array<int> v2v(NumOfVertices);
2010  for (int i = 0; i < v2v.Size(); i++)
2011  {
2012  v2v[i] = i;
2013  }
2014  int num_per_ent;
2015  int num_nodes;
2016  int slave, master;
2017  input >> num_per_ent;
2018  getline(input, buff); // Read end-of-line
2019  for (int i = 0; i < num_per_ent; i++)
2020  {
2021  getline(input, buff); // Read and ignore entity dimension and tags
2022  getline(input, buff); // Read and ignore affine mapping
2023  // Read master/slave vertex pairs
2024  input >> num_nodes;
2025  for (int j=0; j<num_nodes; j++)
2026  {
2027  input >> slave >> master;
2028  v2v[slave - 1] = master - 1;
2029  }
2030  getline(input, buff); // Read end-of-line
2031  }
2032 
2033  // Convert nodes to discontinuous GridFunction (if they aren't already)
2034  if (mesh_order == 1)
2035  {
2036  this->SetCurvature(1, true, spaceDim, Ordering::byVDIM);
2037  }
2038 
2039  // Replace "slave" vertex indices in the element connectivity
2040  // with their corresponding "master" vertex indices.
2041  for (int i = 0; i < this->GetNE(); i++)
2042  {
2043  Element *el = this->GetElement(i);
2044  int *v = el->GetVertices();
2045  int nv = el->GetNVertices();
2046  for (int j = 0; j < nv; j++)
2047  {
2048  v[j] = v2v[v[j]];
2049  }
2050  }
2051  // Replace "slave" vertex indices in the boundary element connectivity
2052  // with their corresponding "master" vertex indices.
2053  for (int i = 0; i < this->GetNBE(); i++)
2054  {
2055  Element *el = this->GetBdrElement(i);
2056  int *v = el->GetVertices();
2057  int nv = el->GetNVertices();
2058  for (int j = 0; j < nv; j++)
2059  {
2060  v[j] = v2v[v[j]];
2061  }
2062  }
2063  }
2064  } // we reach the end of the file
2065 
2066  this->RemoveUnusedVertices();
2067  if (periodic)
2068  {
2069  this->RemoveInternalBoundaries();
2070  }
2071  this->FinalizeTopology();
2072 
2073  // If a high order coordinate field was created project it onto the mesh
2074  if (mesh_order > 1)
2075  {
2076  SetCurvature(mesh_order, periodic, spaceDim, Ordering::byVDIM);
2077 
2078  VectorGridFunctionCoefficient NodesCoef(&Nodes_gf);
2079  Nodes->ProjectCoefficient(NodesCoef);
2080  }
2081 }
2082 
2083 
2084 #ifdef MFEM_USE_NETCDF
2085 void Mesh::ReadCubit(const char *filename, int &curved, int &read_gf)
2086 {
2087  read_gf = 0;
2088 
2089  // curved set to zero will change if mesh is indeed curved
2090  curved = 0;
2091 
2092  const int sideMapTri3[3][2] =
2093  {
2094  {1,2},
2095  {2,3},
2096  {3,1},
2097  };
2098 
2099  const int sideMapQuad4[4][2] =
2100  {
2101  {1,2},
2102  {2,3},
2103  {3,4},
2104  {4,1},
2105  };
2106 
2107  const int sideMapTri6[3][3] =
2108  {
2109  {1,2,4},
2110  {2,3,5},
2111  {3,1,6},
2112  };
2113 
2114  const int sideMapQuad9[4][3] =
2115  {
2116  {1,2,5},
2117  {2,3,6},
2118  {3,4,7},
2119  {4,1,8},
2120  };
2121 
2122  const int sideMapTet4[4][3] =
2123  {
2124  {1,2,4},
2125  {2,3,4},
2126  {1,4,3},
2127  {1,3,2}
2128  };
2129 
2130  const int sideMapTet10[4][6] =
2131  {
2132  {1,2,4,5,9,8},
2133  {2,3,4,6,10,9},
2134  {1,4,3,8,10,7},
2135  {1,3,2,7,6,5}
2136  };
2137 
2138  const int sideMapHex8[6][4] =
2139  {
2140  {1,2,6,5},
2141  {2,3,7,6},
2142  {4,3,7,8},
2143  {1,4,8,5},
2144  {1,4,3,2},
2145  {5,8,7,6}
2146  };
2147 
2148  const int sideMapHex27[6][9] =
2149  {
2150  {1,2,6,5,9,14,17,13,26},
2151  {2,3,7,6,10,15,18,14,25},
2152  {4,3,7,8,11,15,19,16,27},
2153  {1,4,8,5,12,16,20,13,24},
2154  {1,4,3,2,12,11,10,9,22},
2155  {5,8,7,6,20,19,18,17,23}
2156  };
2157 
2158 
2159  // 1,2,3,4,5,6,7,8,9,10
2160  const int mfemToGenesisTet10[10] = {1,2,3,4,5,7,8,6,9,10};
2161 
2162  // 1,2,3,4,5,6,7,8,9,10,11,
2163  const int mfemToGenesisHex27[27] = {1,2,3,4,5,6,7,8,9,10,11,
2164  // 12,13,14,15,16,17,18,19
2165  12,17,18,19,20,13,14,15,
2166  // 20,21,22,23,24,25,26,27
2167  16,22,26,25,27,24,23,21
2168  };
2169 
2170  const int mfemToGenesisTri6[6] = {1,2,3,4,5,6};
2171  const int mfemToGenesisQuad9[9] = {1,2,3,4,5,6,7,8,9};
2172 
2173 
2174  // error handling.
2175  int retval;
2176 
2177  // dummy string
2178  char str_dummy[256];
2179 
2180  char temp_str[256];
2181  int temp_id;
2182 
2183  // open the file.
2184  int ncid;
2185  if ((retval = nc_open(filename, NC_NOWRITE, &ncid)))
2186  {
2187  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
2188  }
2189 
2190  // read important dimensions
2191 
2192  int id;
2193  size_t num_dim=0, num_nodes=0, num_elem=0, num_el_blk=0, num_side_sets=0;
2194 
2195  if ((retval = nc_inq_dimid(ncid, "num_dim", &id)) ||
2196  (retval = nc_inq_dim(ncid, id, str_dummy, &num_dim)) ||
2197 
2198  (retval = nc_inq_dimid(ncid, "num_nodes", &id)) ||
2199  (retval = nc_inq_dim(ncid, id, str_dummy, &num_nodes)) ||
2200 
2201  (retval = nc_inq_dimid(ncid, "num_elem", &id)) ||
2202  (retval = nc_inq_dim(ncid, id, str_dummy, &num_elem)) ||
2203 
2204  (retval = nc_inq_dimid(ncid, "num_el_blk", &id)) ||
2205  (retval = nc_inq_dim(ncid, id, str_dummy, &num_el_blk)))
2206  {
2207  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
2208  }
2209  if ((retval = nc_inq_dimid(ncid, "num_side_sets", &id)) ||
2210  (retval = nc_inq_dim(ncid, id, str_dummy, &num_side_sets)))
2211  {
2212  num_side_sets = 0;
2213  }
2214 
2215  Dim = num_dim;
2216 
2217  // create arrays for element blocks
2218  size_t *num_el_in_blk = new size_t[num_el_blk];
2219  size_t num_node_per_el;
2220 
2221  int previous_num_node_per_el = 0;
2222  for (int i = 0; i < (int) num_el_blk; i++)
2223  {
2224  sprintf(temp_str, "num_el_in_blk%d", i+1);
2225  if ((retval = nc_inq_dimid(ncid, temp_str, &temp_id)) ||
2226  (retval = nc_inq_dim(ncid, temp_id, str_dummy, &num_el_in_blk[i])))
2227  {
2228  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
2229  }
2230 
2231  sprintf(temp_str, "num_nod_per_el%d", i+1);
2232  if ((retval = nc_inq_dimid(ncid, temp_str, &temp_id)) ||
2233  (retval = nc_inq_dim(ncid, temp_id, str_dummy, &num_node_per_el)))
2234  {
2235  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
2236  }
2237 
2238  // check for different element types in each block
2239  // which is not currently supported
2240  if (i != 0)
2241  {
2242  if ((int) num_node_per_el != previous_num_node_per_el)
2243  {
2244  MFEM_ABORT("Element blocks of different element types not supported");
2245  }
2246  }
2247  previous_num_node_per_el = num_node_per_el;
2248  }
2249 
2250  // Determine CUBIT element and face type
2251  enum CubitElementType
2252  {
2253  ELEMENT_TRI3,
2254  ELEMENT_TRI6,
2255  ELEMENT_QUAD4,
2256  ELEMENT_QUAD9,
2257  ELEMENT_TET4,
2258  ELEMENT_TET10,
2259  ELEMENT_HEX8,
2260  ELEMENT_HEX27
2261  };
2262 
2263  enum CubitFaceType
2264  {
2265  FACE_EDGE2,
2266  FACE_EDGE3,
2267  FACE_TRI3,
2268  FACE_TRI6,
2269  FACE_QUAD4,
2270  FACE_QUAD9
2271  };
2272 
2273  CubitElementType cubit_element_type = ELEMENT_TRI3; // suppress a warning
2274  CubitFaceType cubit_face_type = FACE_EDGE2; // suppress a warning
2275  int num_element_linear_nodes = 0; // initialize to suppress a warning
2276 
2277  if (num_dim == 2)
2278  {
2279  switch (num_node_per_el)
2280  {
2281  case (3) :
2282  {
2283  cubit_element_type = ELEMENT_TRI3;
2284  cubit_face_type = FACE_EDGE2;
2285  num_element_linear_nodes = 3;
2286  break;
2287  }
2288  case (6) :
2289  {
2290  cubit_element_type = ELEMENT_TRI6;
2291  cubit_face_type = FACE_EDGE3;
2292  num_element_linear_nodes = 3;
2293  break;
2294  }
2295  case (4) :
2296  {
2297  cubit_element_type = ELEMENT_QUAD4;
2298  cubit_face_type = FACE_EDGE2;
2299  num_element_linear_nodes = 4;
2300  break;
2301  }
2302  case (9) :
2303  {
2304  cubit_element_type = ELEMENT_QUAD9;
2305  cubit_face_type = FACE_EDGE3;
2306  num_element_linear_nodes = 4;
2307  break;
2308  }
2309  default :
2310  {
2311  MFEM_ABORT("Don't know what to do with a " << num_node_per_el <<
2312  " node 2D element\n");
2313  }
2314  }
2315  }
2316  else if (num_dim == 3)
2317  {
2318  switch (num_node_per_el)
2319  {
2320  case (4) :
2321  {
2322  cubit_element_type = ELEMENT_TET4;
2323  cubit_face_type = FACE_TRI3;
2324  num_element_linear_nodes = 4;
2325  break;
2326  }
2327  case (10) :
2328  {
2329  cubit_element_type = ELEMENT_TET10;
2330  cubit_face_type = FACE_TRI6;
2331  num_element_linear_nodes = 4;
2332  break;
2333  }
2334  case (8) :
2335  {
2336  cubit_element_type = ELEMENT_HEX8;
2337  cubit_face_type = FACE_QUAD4;
2338  num_element_linear_nodes = 8;
2339  break;
2340  }
2341  case (27) :
2342  {
2343  cubit_element_type = ELEMENT_HEX27;
2344  cubit_face_type = FACE_QUAD9;
2345  num_element_linear_nodes = 8;
2346  break;
2347  }
2348  default :
2349  {
2350  MFEM_ABORT("Don't know what to do with a " << num_node_per_el <<
2351  " node 3D element\n");
2352  }
2353  }
2354  }
2355  else
2356  {
2357  MFEM_ABORT("Invalid dimension: num_dim = " << num_dim);
2358  }
2359 
2360  // Determine order of elements
2361  int order = 0;
2362  if (cubit_element_type == ELEMENT_TRI3 || cubit_element_type == ELEMENT_QUAD4 ||
2363  cubit_element_type == ELEMENT_TET4 || cubit_element_type == ELEMENT_HEX8)
2364  {
2365  order = 1;
2366  }
2367  else if (cubit_element_type == ELEMENT_TRI6 ||
2368  cubit_element_type == ELEMENT_QUAD9 ||
2369  cubit_element_type == ELEMENT_TET10 || cubit_element_type == ELEMENT_HEX27)
2370  {
2371  order = 2;
2372  }
2373 
2374  // create array for number of sides in side sets
2375  size_t *num_side_in_ss = new size_t[num_side_sets];
2376  for (int i = 0; i < (int) num_side_sets; i++)
2377  {
2378  sprintf(temp_str, "num_side_ss%d", i+1);
2379  if ((retval = nc_inq_dimid(ncid, temp_str, &temp_id)) ||
2380  (retval = nc_inq_dim(ncid, temp_id, str_dummy, &num_side_in_ss[i])))
2381  {
2382  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
2383  }
2384  }
2385 
2386  // read the coordinates
2387  double *coordx = new double[num_nodes];
2388  double *coordy = new double[num_nodes];
2389  double *coordz = new double[num_nodes];
2390 
2391  if ((retval = nc_inq_varid(ncid, "coordx", &id)) ||
2392  (retval = nc_get_var_double(ncid, id, coordx)) ||
2393  (retval = nc_inq_varid(ncid, "coordy", &id)) ||
2394  (retval = nc_get_var_double(ncid, id, coordy)))
2395  {
2396  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
2397  }
2398 
2399  if (num_dim == 3)
2400  {
2401  if ((retval = nc_inq_varid(ncid, "coordz", &id)) ||
2402  (retval = nc_get_var_double(ncid, id, coordz)))
2403  {
2404  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
2405  }
2406  }
2407 
2408  // read the element blocks
2409  int **elem_blk = new int*[num_el_blk];
2410  for (int i = 0; i < (int) num_el_blk; i++)
2411  {
2412  elem_blk[i] = new int[num_el_in_blk[i] * num_node_per_el];
2413  sprintf(temp_str, "connect%d", i+1);
2414  if ((retval = nc_inq_varid(ncid, temp_str, &temp_id)) ||
2415  (retval = nc_get_var_int(ncid, temp_id, elem_blk[i])))
2416  {
2417  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
2418  }
2419  }
2420  int *ebprop = new int[num_el_blk];
2421  if ((retval = nc_inq_varid(ncid, "eb_prop1", &id)) ||
2422  (retval = nc_get_var_int(ncid, id, ebprop)))
2423  {
2424  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
2425  }
2426 
2427  // read the side sets, a side is is given by (element, face) pairs
2428 
2429  int **elem_ss = new int*[num_side_sets];
2430  int **side_ss = new int*[num_side_sets];
2431 
2432  for (int i = 0; i < (int) num_side_sets; i++)
2433  {
2434  elem_ss[i] = new int[num_side_in_ss[i]];
2435  side_ss[i] = new int[num_side_in_ss[i]];
2436 
2437  sprintf(temp_str, "elem_ss%d", i+1);
2438  if ((retval = nc_inq_varid(ncid, temp_str, &temp_id)) ||
2439  (retval = nc_get_var_int(ncid, temp_id, elem_ss[i])))
2440  {
2441  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
2442  }
2443 
2444  sprintf(temp_str,"side_ss%d",i+1);
2445  if ((retval = nc_inq_varid(ncid, temp_str, &temp_id)) ||
2446  (retval = nc_get_var_int(ncid, temp_id, side_ss[i])))
2447  {
2448  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
2449  }
2450  }
2451 
2452  int *ssprop = new int[num_side_sets];
2453  if ((num_side_sets > 0) &&
2454  ((retval = nc_inq_varid(ncid, "ss_prop1", &id)) ||
2455  (retval = nc_get_var_int(ncid, id, ssprop))))
2456  {
2457  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
2458  }
2459 
2460  // convert (elem,side) pairs to 2D elements
2461 
2462 
2463  int num_face_nodes = 0;
2464  int num_face_linear_nodes = 0;
2465 
2466  switch (cubit_face_type)
2467  {
2468  case (FACE_EDGE2):
2469  {
2470  num_face_nodes = 2;
2471  num_face_linear_nodes = 2;
2472  break;
2473  }
2474  case (FACE_EDGE3):
2475  {
2476  num_face_nodes = 3;
2477  num_face_linear_nodes = 2;
2478  break;
2479  }
2480  case (FACE_TRI3):
2481  {
2482  num_face_nodes = 3;
2483  num_face_linear_nodes = 3;
2484  break;
2485  }
2486  case (FACE_TRI6):
2487  {
2488  num_face_nodes = 6;
2489  num_face_linear_nodes = 3;
2490  break;
2491  }
2492  case (FACE_QUAD4):
2493  {
2494  num_face_nodes = 4;
2495  num_face_linear_nodes = 4;
2496  break;
2497  }
2498  case (FACE_QUAD9):
2499  {
2500  num_face_nodes = 9;
2501  num_face_linear_nodes = 4;
2502  break;
2503  }
2504  }
2505 
2506  // given a global element number, determine the element block and local
2507  // element number
2508  int *start_of_block = new int[num_el_blk+1];
2509  start_of_block[0] = 0;
2510  for (int i = 1; i < (int) num_el_blk+1; i++)
2511  {
2512  start_of_block[i] = start_of_block[i-1] + num_el_in_blk[i-1];
2513  }
2514 
2515  int **ss_node_id = new int*[num_side_sets];
2516 
2517  for (int i = 0; i < (int) num_side_sets; i++)
2518  {
2519  ss_node_id[i] = new int[num_side_in_ss[i]*num_face_nodes];
2520  for (int j = 0; j < (int) num_side_in_ss[i]; j++)
2521  {
2522  int glob_ind = elem_ss[i][j]-1;
2523  int iblk = 0;
2524  int loc_ind;
2525  while (iblk < (int) num_el_blk && glob_ind >= start_of_block[iblk+1])
2526  {
2527  iblk++;
2528  }
2529  if (iblk >= (int) num_el_blk)
2530  {
2531  MFEM_ABORT("Sideset element does not exist");
2532  }
2533  loc_ind = glob_ind - start_of_block[iblk];
2534  int this_side = side_ss[i][j];
2535  int ielem = loc_ind*num_node_per_el;
2536 
2537  for (int k = 0; k < num_face_nodes; k++)
2538  {
2539  int inode;
2540  switch (cubit_element_type)
2541  {
2542  case (ELEMENT_TRI3):
2543  {
2544  inode = sideMapTri3[this_side-1][k];
2545  break;
2546  }
2547  case (ELEMENT_TRI6):
2548  {
2549  inode = sideMapTri6[this_side-1][k];
2550  break;
2551  }
2552  case (ELEMENT_QUAD4):
2553  {
2554  inode = sideMapQuad4[this_side-1][k];
2555  break;
2556  }
2557  case (ELEMENT_QUAD9):
2558  {
2559  inode = sideMapQuad9[this_side-1][k];
2560  break;
2561  }
2562  case (ELEMENT_TET4):
2563  {
2564  inode = sideMapTet4[this_side-1][k];
2565  break;
2566  }
2567  case (ELEMENT_TET10):
2568  {
2569  inode = sideMapTet10[this_side-1][k];
2570  break;
2571  }
2572  case (ELEMENT_HEX8):
2573  {
2574  inode = sideMapHex8[this_side-1][k];
2575  break;
2576  }
2577  case (ELEMENT_HEX27):
2578  {
2579  inode = sideMapHex27[this_side-1][k];
2580  break;
2581  }
2582  }
2583  ss_node_id[i][j*num_face_nodes+k] =
2584  elem_blk[iblk][ielem + inode - 1];
2585  }
2586  }
2587  }
2588 
2589  // we need another node ID mapping since MFEM needs contiguous vertex IDs
2590  std::vector<int> uniqueVertexID;
2591 
2592  for (int iblk = 0; iblk < (int) num_el_blk; iblk++)
2593  {
2594  for (int i = 0; i < (int) num_el_in_blk[iblk]; i++)
2595  {
2596  for (int j = 0; j < num_element_linear_nodes; j++)
2597  {
2598  uniqueVertexID.push_back(elem_blk[iblk][i*num_node_per_el + j]);
2599  }
2600  }
2601  }
2602  std::sort(uniqueVertexID.begin(), uniqueVertexID.end());
2603  std::vector<int>::iterator newEnd;
2604  newEnd = std::unique(uniqueVertexID.begin(), uniqueVertexID.end());
2605  uniqueVertexID.resize(std::distance(uniqueVertexID.begin(), newEnd));
2606 
2607  // OK at this point uniqueVertexID contains a list of all the nodes that are
2608  // actually used by the mesh, 1-based, and sorted. We need to invert this
2609  // list, the inverse is a map
2610 
2611  std::map<int,int> cubitToMFEMVertMap;
2612  for (int i = 0; i < (int) uniqueVertexID.size(); i++)
2613  {
2614  cubitToMFEMVertMap[uniqueVertexID[i]] = i+1;
2615  }
2616  MFEM_ASSERT(cubitToMFEMVertMap.size() == uniqueVertexID.size(),
2617  "This should never happen\n");
2618 
2619  // OK now load up the MFEM mesh structures
2620 
2621  // load up the vertices
2622 
2623  NumOfVertices = uniqueVertexID.size();
2624  vertices.SetSize(NumOfVertices);
2625  for (int i = 0; i < (int) uniqueVertexID.size(); i++)
2626  {
2627  vertices[i](0) = coordx[uniqueVertexID[i] - 1];
2628  vertices[i](1) = coordy[uniqueVertexID[i] - 1];
2629  if (Dim == 3)
2630  {
2631  vertices[i](2) = coordz[uniqueVertexID[i] - 1];
2632  }
2633  }
2634 
2635  NumOfElements = num_elem;
2636  elements.SetSize(num_elem);
2637  int elcount = 0;
2638  int renumberedVertID[8];
2639  for (int iblk = 0; iblk < (int) num_el_blk; iblk++)
2640  {
2641  int NumNodePerEl = num_node_per_el;
2642  for (int i = 0; i < (int) num_el_in_blk[iblk]; i++)
2643  {
2644  for (int j = 0; j < num_element_linear_nodes; j++)
2645  {
2646  renumberedVertID[j] =
2647  cubitToMFEMVertMap[elem_blk[iblk][i*NumNodePerEl+j]]-1;
2648  }
2649 
2650  switch (cubit_element_type)
2651  {
2652  case (ELEMENT_TRI3):
2653  case (ELEMENT_TRI6):
2654  {
2655  elements[elcount] = new Triangle(renumberedVertID,ebprop[iblk]);
2656  break;
2657  }
2658  case (ELEMENT_QUAD4):
2659  case (ELEMENT_QUAD9):
2660  {
2661  elements[elcount] = new Quadrilateral(renumberedVertID,ebprop[iblk]);
2662  break;
2663  }
2664  case (ELEMENT_TET4):
2665  case (ELEMENT_TET10):
2666  {
2667 #ifdef MFEM_USE_MEMALLOC
2668  elements[elcount] = TetMemory.Alloc();
2669  elements[elcount]->SetVertices(renumberedVertID);
2670  elements[elcount]->SetAttribute(ebprop[iblk]);
2671 #else
2672  elements[elcount] = new Tetrahedron(renumberedVertID,
2673  ebprop[iblk]);
2674 #endif
2675  break;
2676  }
2677  case (ELEMENT_HEX8):
2678  case (ELEMENT_HEX27):
2679  {
2680  elements[elcount] = new Hexahedron(renumberedVertID,ebprop[iblk]);
2681  break;
2682  }
2683  }
2684  elcount++;
2685  }
2686  }
2687 
2688  // load up the boundary elements
2689 
2690  NumOfBdrElements = 0;
2691  for (int iss = 0; iss < (int) num_side_sets; iss++)
2692  {
2693  NumOfBdrElements += num_side_in_ss[iss];
2694  }
2695  boundary.SetSize(NumOfBdrElements);
2696  int sidecount = 0;
2697  for (int iss = 0; iss < (int) num_side_sets; iss++)
2698  {
2699  for (int i = 0; i < (int) num_side_in_ss[iss]; i++)
2700  {
2701  for (int j = 0; j < num_face_linear_nodes; j++)
2702  {
2703  renumberedVertID[j] =
2704  cubitToMFEMVertMap[ss_node_id[iss][i*num_face_nodes+j]] - 1;
2705  }
2706  switch (cubit_face_type)
2707  {
2708  case (FACE_EDGE2):
2709  case (FACE_EDGE3):
2710  {
2711  boundary[sidecount] = new Segment(renumberedVertID,ssprop[iss]);
2712  break;
2713  }
2714  case (FACE_TRI3):
2715  case (FACE_TRI6):
2716  {
2717  boundary[sidecount] = new Triangle(renumberedVertID,ssprop[iss]);
2718  break;
2719  }
2720  case (FACE_QUAD4):
2721  case (FACE_QUAD9):
2722  {
2723  boundary[sidecount] = new Quadrilateral(renumberedVertID,ssprop[iss]);
2724  break;
2725  }
2726  }
2727  sidecount++;
2728  }
2729  }
2730 
2731  if (order == 2)
2732  {
2733  curved = 1;
2734  int *mymap = NULL;
2735 
2736  switch (cubit_element_type)
2737  {
2738  case (ELEMENT_TRI6):
2739  {
2740  mymap = (int *) mfemToGenesisTri6;
2741  break;
2742  }
2743  case (ELEMENT_QUAD9):
2744  {
2745  mymap = (int *) mfemToGenesisQuad9;
2746  break;
2747  }
2748  case (ELEMENT_TET10):
2749  {
2750  mymap = (int *) mfemToGenesisTet10;
2751  break;
2752  }
2753  case (ELEMENT_HEX27):
2754  {
2755  mymap = (int *) mfemToGenesisHex27;
2756  break;
2757  }
2758  case (ELEMENT_TRI3):
2759  case (ELEMENT_QUAD4):
2760  case (ELEMENT_TET4):
2761  case (ELEMENT_HEX8):
2762  {
2763  MFEM_ABORT("Something went wrong. Linear elements detected when order is 2.");
2764  break;
2765  }
2766  }
2767 
2768  FinalizeTopology();
2769 
2770  // Define quadratic FE space
2771  FiniteElementCollection *fec = new H1_FECollection(2,3);
2772  FiniteElementSpace *fes = new FiniteElementSpace(this, fec, Dim,
2773  Ordering::byVDIM);
2774  Nodes = new GridFunction(fes);
2775  Nodes->MakeOwner(fec); // Nodes will destroy 'fec' and 'fes'
2776  own_nodes = 1;
2777 
2778  // int nTotDofs = fes->GetNDofs();
2779  // int nTotVDofs = fes->GetVSize();
2780  // mfem::out << endl << "nTotDofs = " << nTotDofs << " nTotVDofs "
2781  // << nTotVDofs << endl << endl;
2782 
2783  for (int i = 0; i < NumOfElements; i++)
2784  {
2785  Array<int> dofs;
2786 
2787  fes->GetElementDofs(i, dofs);
2788  Array<int> vdofs;
2789  vdofs.SetSize(dofs.Size());
2790  for (int l = 0; l < dofs.Size(); l++) { vdofs[l] = dofs[l]; }
2791  fes->DofsToVDofs(vdofs);
2792  int iblk = 0;
2793  int loc_ind;
2794  while (iblk < (int) num_el_blk && i >= start_of_block[iblk+1]) { iblk++; }
2795  loc_ind = i - start_of_block[iblk];
2796  for (int j = 0; j < dofs.Size(); j++)
2797  {
2798  int point_id = elem_blk[iblk][loc_ind*num_node_per_el + mymap[j] - 1] - 1;
2799  (*Nodes)(vdofs[j]) = coordx[point_id];
2800  (*Nodes)(vdofs[j]+1) = coordy[point_id];
2801  if (Dim == 3)
2802  {
2803  (*Nodes)(vdofs[j]+2) = coordz[point_id];
2804  }
2805  }
2806  }
2807  }
2808 
2809  // clean up all netcdf stuff
2810 
2811  nc_close(ncid);
2812 
2813  for (int i = 0; i < (int) num_side_sets; i++)
2814  {
2815  delete [] elem_ss[i];
2816  delete [] side_ss[i];
2817  }
2818 
2819  delete [] elem_ss;
2820  delete [] side_ss;
2821  delete [] num_el_in_blk;
2822  delete [] num_side_in_ss;
2823  delete [] coordx;
2824  delete [] coordy;
2825  delete [] coordz;
2826 
2827  for (int i = 0; i < (int) num_el_blk; i++)
2828  {
2829  delete [] elem_blk[i];
2830  }
2831 
2832  delete [] elem_blk;
2833  delete [] start_of_block;
2834 
2835  for (int i = 0; i < (int) num_side_sets; i++)
2836  {
2837  delete [] ss_node_id[i];
2838  }
2839  delete [] ss_node_id;
2840  delete [] ebprop;
2841  delete [] ssprop;
2842 
2843 }
2844 #endif // #ifdef MFEM_USE_NETCDF
2845 
2846 } // namespace mfem
Arbitrary order non-uniform rational B-splines (NURBS) finite elements.
Definition: fe_coll.hpp:372
Vector bb_max
Definition: ex9.cpp:64
Mesh * Make3D(int nsteps, double rstep, double aspect, int order, bool sfc)
Definition: polar-nc.cpp:370
int Size() const
Return the logical size of the array.
Definition: array.hpp:124
Class for grid function - Vector with associated FE space.
Definition: gridfunc.hpp:30
virtual void GetVertices(Array< int > &v) const =0
Returns element&#39;s vertices.
void GmshHOSegmentMapping(int order, int *map)
Generate Gmsh vertex mapping for a Segment.
Definition: gmsh.cpp:378
void SetSize(int s)
Resize the vector to size s.
Definition: vector.hpp:459
void MakeOwner(FiniteElementCollection *_fec)
Make the GridFunction the owner of fec and fes.
Definition: gridfunc.hpp:115
int Size() const
Returns the size of the vector.
Definition: vector.hpp:160
Data type for vertex.
Definition: vertex.hpp:22
virtual void SetVertices(const int *ind)
Set the vertices according to the given input.
Data type quadrilateral element.
Data type Wedge element.
Definition: wedge.hpp:22
void skip_comment_lines(std::istream &is, const char comment_char)
Check if the stream starts with comment_char. If so skip it.
Definition: text.hpp:28
void DeleteAll()
Delete the whole array.
Definition: array.hpp:821
Mesh * Make2D(int nsteps, double rstep, double phi, double aspect, int order, bool sfc)
Definition: polar-nc.cpp:49
Data type hexahedron element.
Definition: hexahedron.hpp:22
int Append(const T &el)
Append element &#39;el&#39; to array, resize if necessary.
Definition: array.hpp:726
Type
Constants for the classes derived from Element.
Definition: element.hpp:41
virtual void GetElementDofs(int i, Array< int > &dofs) const
Returns indexes of degrees of freedom in array dofs for i&#39;th element.
Definition: fespace.cpp:1696
Data type triangle element.
Definition: triangle.hpp:23
A class for non-conforming AMR on higher-order hexahedral, prismatic, quadrilateral or triangular mes...
Definition: ncmesh.hpp:102
void GmshHOQuadrilateralMapping(int order, int *map)
Generate Gmsh vertex mapping for a Quadrilateral.
Definition: gmsh.cpp:403
Data type tetrahedron element.
Definition: tetrahedron.hpp:22
Vector bb_min
Definition: ex9.cpp:64
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition: fespace.hpp:87
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition: fe_coll.hpp:26
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition: array.hpp:654
void GmshHOTriangleMapping(int order, int *map)
Generate Gmsh vertex mapping for a Triangle.
Definition: gmsh.cpp:388
void GmshHOTetrahedronMapping(int order, int *map)
Generate Gmsh vertex mapping for a Tetrahedron.
Definition: gmsh.cpp:417
double a
Definition: lissajous.cpp:41
void Destroy()
Destroy a vector.
Definition: vector.hpp:530
int index(int i, int j, int nx, int ny)
Definition: life.cpp:241
virtual int GetNVertices() const =0
void SetAttribute(const int attr)
Set element&#39;s attribute.
Definition: element.hpp:58
Piecewise-(bi)quadratic continuous finite elements.
Definition: fe_coll.hpp:455
virtual void SetSpace(FiniteElementSpace *f)
Associate a new FiniteElementSpace with the GridFunction.
Definition: gridfunc.cpp:180
void filter_dos(std::string &line)
Check for, and remove, a trailing &#39;\r&#39; from and std::string.
Definition: text.hpp:42
Vector data type.
Definition: vector.hpp:51
Data type point element.
Definition: point.hpp:22
Vector coefficient defined by a vector GridFunction.
void GmshHOHexahedronMapping(int order, int *map)
Generate Gmsh vertex mapping for a Hexahedron.
Definition: gmsh.cpp:436
Arbitrary order H1-conforming (continuous) finite elements.
Definition: fe_coll.hpp:159
void GmshHOWedgeMapping(int order, int *map)
Generate Gmsh vertex mapping for a Wedge.
Definition: gmsh.cpp:453
Abstract data type element.
Definition: element.hpp:28
Data type line segment element.
Definition: segment.hpp:22
Arbitrary order &quot;L2-conforming&quot; discontinuous finite elements.
Definition: fe_coll.hpp:221
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Definition: fespace.cpp:108