MFEM  v4.3.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-2021, 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/binaryio.hpp"
15 #include "../general/text.hpp"
16 #include "../general/tinyxml2.h"
17 #include "gmsh.hpp"
18 
19 #include <iostream>
20 #include <cstdio>
21 #include <vector>
22 #include <algorithm>
23 
24 #ifdef MFEM_USE_NETCDF
25 #include "netcdf.h"
26 #endif
27 
28 #ifdef MFEM_USE_ZLIB
29 #include <zlib.h>
30 #endif
31 
32 using namespace std;
33 
34 namespace mfem
35 {
36 
37 bool Mesh::remove_unused_vertices = true;
38 
39 void Mesh::ReadMFEMMesh(std::istream &input, int version, int &curved)
40 {
41  // Read MFEM mesh v1.0 or v1.2 format
42  MFEM_VERIFY(version == 10 || version == 12,
43  "unknown MFEM mesh version");
44 
45  string ident;
46 
47  // read lines beginning with '#' (comments)
48  skip_comment_lines(input, '#');
49  input >> ident; // 'dimension'
50 
51  MFEM_VERIFY(ident == "dimension", "invalid mesh file");
52  input >> Dim;
53 
54  skip_comment_lines(input, '#');
55  input >> ident; // 'elements'
56 
57  MFEM_VERIFY(ident == "elements", "invalid mesh file");
58  input >> NumOfElements;
59  elements.SetSize(NumOfElements);
60  for (int j = 0; j < NumOfElements; j++)
61  {
62  elements[j] = ReadElement(input);
63  }
64 
65  skip_comment_lines(input, '#');
66  input >> ident; // 'boundary'
67 
68  MFEM_VERIFY(ident == "boundary", "invalid mesh file");
69  input >> NumOfBdrElements;
70  boundary.SetSize(NumOfBdrElements);
71  for (int j = 0; j < NumOfBdrElements; j++)
72  {
73  boundary[j] = ReadElement(input);
74  }
75 
76  skip_comment_lines(input, '#');
77  input >> ident; // 'vertices'
78 
79  MFEM_VERIFY(ident == "vertices", "invalid mesh file");
80  input >> NumOfVertices;
81  vertices.SetSize(NumOfVertices);
82 
83  input >> ws >> ident;
84  if (ident != "nodes")
85  {
86  // read the vertices
87  spaceDim = atoi(ident.c_str());
88  for (int j = 0; j < NumOfVertices; j++)
89  {
90  for (int i = 0; i < spaceDim; i++)
91  {
92  input >> vertices[j](i);
93  }
94  }
95  }
96  else
97  {
98  // prepare to read the nodes
99  input >> ws;
100  curved = 1;
101  }
102 
103  // When visualizing solutions on non-conforming grids, PETSc
104  // may dump additional vertices
105  if (remove_unused_vertices) { RemoveUnusedVertices(); }
106 }
107 
108 void Mesh::ReadLineMesh(std::istream &input)
109 {
110  int j,p1,p2,a;
111 
112  Dim = 1;
113 
114  input >> NumOfVertices;
115  vertices.SetSize(NumOfVertices);
116  // Sets vertices and the corresponding coordinates
117  for (j = 0; j < NumOfVertices; j++)
118  {
119  input >> vertices[j](0);
120  }
121 
122  input >> NumOfElements;
123  elements.SetSize(NumOfElements);
124  // Sets elements and the corresponding indices of vertices
125  for (j = 0; j < NumOfElements; j++)
126  {
127  input >> a >> p1 >> p2;
128  elements[j] = new Segment(p1-1, p2-1, a);
129  }
130 
131  int ind[1];
132  input >> NumOfBdrElements;
133  boundary.SetSize(NumOfBdrElements);
134  for (j = 0; j < NumOfBdrElements; j++)
135  {
136  input >> a >> ind[0];
137  ind[0]--;
138  boundary[j] = new Point(ind,a);
139  }
140 }
141 
142 void Mesh::ReadNetgen2DMesh(std::istream &input, int &curved)
143 {
144  int ints[32], attr, n;
145 
146  // Read planar mesh in Netgen format.
147  Dim = 2;
148 
149  // Read the boundary elements.
150  input >> NumOfBdrElements;
151  boundary.SetSize(NumOfBdrElements);
152  for (int i = 0; i < NumOfBdrElements; i++)
153  {
154  input >> attr
155  >> ints[0] >> ints[1];
156  ints[0]--; ints[1]--;
157  boundary[i] = new Segment(ints, attr);
158  }
159 
160  // Read the elements.
161  input >> NumOfElements;
162  elements.SetSize(NumOfElements);
163  for (int i = 0; i < NumOfElements; i++)
164  {
165  input >> attr >> n;
166  for (int j = 0; j < n; j++)
167  {
168  input >> ints[j];
169  ints[j]--;
170  }
171  switch (n)
172  {
173  case 2:
174  elements[i] = new Segment(ints, attr);
175  break;
176  case 3:
177  elements[i] = new Triangle(ints, attr);
178  break;
179  case 4:
180  elements[i] = new Quadrilateral(ints, attr);
181  break;
182  }
183  }
184 
185  if (!curved)
186  {
187  // Read the vertices.
188  input >> NumOfVertices;
189  vertices.SetSize(NumOfVertices);
190  for (int i = 0; i < NumOfVertices; i++)
191  for (int j = 0; j < Dim; j++)
192  {
193  input >> vertices[i](j);
194  }
195  }
196  else
197  {
198  input >> NumOfVertices;
199  vertices.SetSize(NumOfVertices);
200  input >> ws;
201  }
202 }
203 
204 void Mesh::ReadNetgen3DMesh(std::istream &input)
205 {
206  int ints[32], attr;
207 
208  // Read a Netgen format mesh of tetrahedra.
209  Dim = 3;
210 
211  // Read the vertices
212  input >> NumOfVertices;
213 
214  vertices.SetSize(NumOfVertices);
215  for (int i = 0; i < NumOfVertices; i++)
216  for (int j = 0; j < Dim; j++)
217  {
218  input >> vertices[i](j);
219  }
220 
221  // Read the elements
222  input >> NumOfElements;
223  elements.SetSize(NumOfElements);
224  for (int i = 0; i < NumOfElements; i++)
225  {
226  input >> attr;
227  for (int j = 0; j < 4; j++)
228  {
229  input >> ints[j];
230  ints[j]--;
231  }
232 #ifdef MFEM_USE_MEMALLOC
233  Tetrahedron *tet;
234  tet = TetMemory.Alloc();
235  tet->SetVertices(ints);
236  tet->SetAttribute(attr);
237  elements[i] = tet;
238 #else
239  elements[i] = new Tetrahedron(ints, attr);
240 #endif
241  }
242 
243  // Read the boundary information.
244  input >> NumOfBdrElements;
245  boundary.SetSize(NumOfBdrElements);
246  for (int i = 0; i < NumOfBdrElements; i++)
247  {
248  input >> attr;
249  for (int j = 0; j < 3; j++)
250  {
251  input >> ints[j];
252  ints[j]--;
253  }
254  boundary[i] = new Triangle(ints, attr);
255  }
256 }
257 
258 void Mesh::ReadTrueGridMesh(std::istream &input)
259 {
260  int i, j, ints[32], attr;
261  const int buflen = 1024;
262  char buf[buflen];
263 
264  // TODO: find the actual dimension
265  Dim = 3;
266 
267  if (Dim == 2)
268  {
269  int vari;
270  double varf;
271 
272  input >> vari >> NumOfVertices >> vari >> vari >> NumOfElements;
273  input.getline(buf, buflen);
274  input.getline(buf, buflen);
275  input >> vari;
276  input.getline(buf, buflen);
277  input.getline(buf, buflen);
278  input.getline(buf, buflen);
279 
280  // Read the vertices.
281  vertices.SetSize(NumOfVertices);
282  for (i = 0; i < NumOfVertices; i++)
283  {
284  input >> vari >> varf >> vertices[i](0) >> vertices[i](1);
285  input.getline(buf, buflen);
286  }
287 
288  // Read the elements.
289  elements.SetSize(NumOfElements);
290  for (i = 0; i < NumOfElements; i++)
291  {
292  input >> vari >> attr;
293  for (j = 0; j < 4; j++)
294  {
295  input >> ints[j];
296  ints[j]--;
297  }
298  input.getline(buf, buflen);
299  input.getline(buf, buflen);
300  elements[i] = new Quadrilateral(ints, attr);
301  }
302  }
303  else if (Dim == 3)
304  {
305  int vari;
306  double varf;
307  input >> vari >> NumOfVertices >> NumOfElements;
308  input.getline(buf, buflen);
309  input.getline(buf, buflen);
310  input >> vari >> vari >> NumOfBdrElements;
311  input.getline(buf, buflen);
312  input.getline(buf, buflen);
313  input.getline(buf, buflen);
314  // Read the vertices.
315  vertices.SetSize(NumOfVertices);
316  for (i = 0; i < NumOfVertices; i++)
317  {
318  input >> vari >> varf >> vertices[i](0) >> vertices[i](1)
319  >> vertices[i](2);
320  input.getline(buf, buflen);
321  }
322  // Read the elements.
323  elements.SetSize(NumOfElements);
324  for (i = 0; i < NumOfElements; i++)
325  {
326  input >> vari >> attr;
327  for (j = 0; j < 8; j++)
328  {
329  input >> ints[j];
330  ints[j]--;
331  }
332  input.getline(buf, buflen);
333  elements[i] = new Hexahedron(ints, attr);
334  }
335  // Read the boundary elements.
336  boundary.SetSize(NumOfBdrElements);
337  for (i = 0; i < NumOfBdrElements; i++)
338  {
339  input >> attr;
340  for (j = 0; j < 4; j++)
341  {
342  input >> ints[j];
343  ints[j]--;
344  }
345  input.getline(buf, buflen);
346  boundary[i] = new Quadrilateral(ints, attr);
347  }
348  }
349 }
350 
351 // see Tetrahedron::edges
352 const int Mesh::vtk_quadratic_tet[10] =
353 { 0, 1, 2, 3, 4, 7, 5, 6, 8, 9 };
354 
355 // see Wedge::edges & Mesh::GenerateFaces
356 // https://www.vtk.org/doc/nightly/html/classvtkBiQuadraticQuadraticWedge.html
357 const int Mesh::vtk_quadratic_wedge[18] =
358 { 0, 2, 1, 3, 5, 4, 8, 7, 6, 11, 10, 9, 12, 14, 13, 17, 16, 15};
359 
360 // see Hexahedron::edges & Mesh::GenerateFaces
361 const int Mesh::vtk_quadratic_hex[27] =
362 {
363  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
364  24, 22, 21, 23, 20, 25, 26
365 };
366 
367 void Mesh::CreateVTKMesh(const Vector &points, const Array<int> &cell_data,
368  const Array<int> &cell_offsets,
369  const Array<int> &cell_types,
370  const Array<int> &cell_attributes,
371  int &curved, int &read_gf, bool &finalize_topo)
372 {
373  int np = points.Size()/3;
374  Dim = -1;
375  NumOfElements = cell_types.Size();
376  elements.SetSize(NumOfElements);
377 
378  int order = -1;
379  bool legacy_elem = false, lagrange_elem = false;
380 
381  int j = 0;
382  for (int i = 0; i < NumOfElements; i++)
383  {
384  int ct = cell_types[i];
385  Geometry::Type geom = VTKGeometry::GetMFEMGeometry(ct);
386  elements[i] = NewElement(geom);
387  if (cell_attributes.Size() > 0)
388  {
389  elements[i]->SetAttribute(cell_attributes[i]);
390  }
391  // VTK ordering of vertices is the same as MFEM ordering of vertices
392  // for all element types *except* prisms, which require a permutation
393  if (geom == Geometry::PRISM && ct != VTKGeometry::LAGRANGE_PRISM)
394  {
395  int prism_vertices[6];
396  for (int k=0; k<6; ++k)
397  {
398  prism_vertices[k] = cell_data[j+VTKGeometry::PrismMap[k]];
399  }
400  elements[i]->SetVertices(prism_vertices);
401  }
402  else
403  {
404  elements[i]->SetVertices(&cell_data[j]);
405  }
406 
407  int elem_dim = Geometry::Dimension[geom];
408  int elem_order = VTKGeometry::GetOrder(ct, cell_offsets[i] - j);
409 
410  if (VTKGeometry::IsLagrange(ct)) { lagrange_elem = true; }
411  else { legacy_elem = true; }
412 
413  MFEM_VERIFY(Dim == -1 || Dim == elem_dim,
414  "Elements with different dimensions are not supported");
415  MFEM_VERIFY(order == -1 || order == elem_order,
416  "Elements with different orders are not supported");
417  MFEM_VERIFY(legacy_elem != lagrange_elem,
418  "Mixing of legacy and Lagrange cell types is not supported");
419  Dim = elem_dim;
420  order = elem_order;
421  j = cell_offsets[i];
422  }
423 
424  if (order == 1 && !lagrange_elem)
425  {
426  NumOfVertices = np;
427  vertices.SetSize(np);
428  for (int i = 0; i < np; i++)
429  {
430  vertices[i](0) = points(3*i+0);
431  vertices[i](1) = points(3*i+1);
432  vertices[i](2) = points(3*i+2);
433  }
434  // No boundary is defined in a VTK mesh
435  NumOfBdrElements = 0;
436  FinalizeTopology();
437  CheckElementOrientation(true);
438  }
439  else
440  {
441  // The following section of code is shared for legacy quadratic and the
442  // Lagrange high order elements
443  curved = 1;
444 
445  // generate new enumeration for the vertices
446  Array<int> pts_dof(np);
447  pts_dof = -1;
448  // mark vertex points
449  for (int i = 0; i < NumOfElements; i++)
450  {
451  int *v = elements[i]->GetVertices();
452  int nv = elements[i]->GetNVertices();
453  for (int j = 0; j < nv; j++)
454  {
455  if (pts_dof[v[j]] == -1) { pts_dof[v[j]] = 0; }
456  }
457  }
458 
459  // The following loop reorders pts_dofs so vertices are visited in
460  // canonical order
461 
462  // Keep the original ordering of the vertices
463  int i, n;
464  for (n = i = 0; i < np; i++)
465  {
466  if (pts_dof[i] != -1)
467  {
468  pts_dof[i] = n++;
469  }
470  }
471  // update the element vertices
472  for (int i = 0; i < NumOfElements; i++)
473  {
474  int *v = elements[i]->GetVertices();
475  int nv = elements[i]->GetNVertices();
476  for (int j = 0; j < nv; j++)
477  {
478  v[j] = pts_dof[v[j]];
479  }
480  }
481  // Define the 'vertices' from the 'points' through the 'pts_dof' map
482  NumOfVertices = n;
483  vertices.SetSize(n);
484  for (int i = 0; i < np; i++)
485  {
486  int j = pts_dof[i];
487  if (j != -1)
488  {
489  vertices[j](0) = points(3*i+0);
490  vertices[j](1) = points(3*i+1);
491  vertices[j](2) = points(3*i+2);
492  }
493  }
494 
495  // No boundary is defined in a VTK mesh
496  NumOfBdrElements = 0;
497 
498  // determine spaceDim based on min/max differences detected each dimension
499  if (vertices.Size() > 0)
500  {
501  double min_value, max_value;
502  for (int d=0; d<3; ++d)
503  {
504  min_value = max_value = vertices[0](d);
505  for (int i = 1; i < vertices.Size(); i++)
506  {
507  min_value = std::min(min_value,vertices[i](d));
508  max_value = std::max(max_value,vertices[i](d));
509  if (min_value != max_value)
510  {
511  spaceDim++;
512  break;
513  }
514  }
515  }
516  }
517  // Generate faces and edges so that we can define
518  // FE space on the mesh
519  FinalizeTopology();
520 
522  FiniteElementSpace *fes;
523  if (legacy_elem)
524  {
525  // Define quadratic FE space
526  fec = new QuadraticFECollection;
527  fes = new FiniteElementSpace(this, fec, spaceDim);
528  Nodes = new GridFunction(fes);
529  Nodes->MakeOwner(fec); // Nodes will destroy 'fec' and 'fes'
530  own_nodes = 1;
531 
532  // Map vtk points to edge/face/element dofs
533  Array<int> dofs;
534  for (int i = 0; i < NumOfElements; i++)
535  {
536  fes->GetElementDofs(i, dofs);
537  const int *vtk_mfem;
538  switch (elements[i]->GetGeometryType())
539  {
540  case Geometry::TRIANGLE:
541  case Geometry::SQUARE:
542  vtk_mfem = vtk_quadratic_hex; break; // identity map
543  case Geometry::TETRAHEDRON:
544  vtk_mfem = vtk_quadratic_tet; break;
545  case Geometry::CUBE:
546  vtk_mfem = vtk_quadratic_hex; break;
547  case Geometry::PRISM:
548  vtk_mfem = vtk_quadratic_wedge; break;
549  default:
550  vtk_mfem = NULL; // suppress a warning
551  break;
552  }
553 
554  int offset = (i == 0) ? 0 : cell_offsets[i-1];
555  for (int j = 0; j < dofs.Size(); j++)
556  {
557  if (pts_dof[cell_data[offset+j]] == -1)
558  {
559  pts_dof[cell_data[offset+j]] = dofs[vtk_mfem[j]];
560  }
561  else
562  {
563  if (pts_dof[cell_data[offset+j]] != dofs[vtk_mfem[j]])
564  {
565  MFEM_ABORT("VTK mesh: inconsistent quadratic mesh!");
566  }
567  }
568  }
569  }
570  }
571  else
572  {
573  // Define H1 FE space
574  fec = new H1_FECollection(order,Dim,BasisType::ClosedUniform);
575  fes = new FiniteElementSpace(this, fec, spaceDim);
576  Nodes = new GridFunction(fes);
577  Nodes->MakeOwner(fec); // Nodes will destroy 'fec' and 'fes'
578  own_nodes = 1;
579  Array<int> dofs;
580 
581  std::map<Geometry::Type,Array<int>> vtk_inv_maps;
582  std::map<Geometry::Type,const Array<int>*> lex_orderings;
583 
584  int i, n;
585  for (n = i = 0; i < NumOfElements; i++)
586  {
587  Geometry::Type geom = GetElementBaseGeometry(i);
588  fes->GetElementDofs(i, dofs);
589 
590  Array<int> &vtk_inv_map = vtk_inv_maps[geom];
591  if (vtk_inv_map.Size() == 0)
592  {
593  Array<int> vtk_map;
594  CreateVTKElementConnectivity(vtk_map, geom, order);
595  vtk_inv_map.SetSize(vtk_map.Size());
596  for (int j=0; j<vtk_map.Size(); ++j)
597  {
598  vtk_inv_map[vtk_map[j]] = j;
599  }
600  }
601  const Array<int> *&lex_ordering = lex_orderings[geom];
602  if (!lex_ordering)
603  {
604  const FiniteElement *fe = fes->GetFE(i);
605  const NodalFiniteElement *nodal_fe =
606  dynamic_cast<const NodalFiniteElement*>(fe);
607  MFEM_ASSERT(nodal_fe != NULL, "Unsupported element type");
608  lex_ordering = &nodal_fe->GetLexicographicOrdering();
609  }
610 
611  for (int lex_idx = 0; lex_idx < dofs.Size(); lex_idx++)
612  {
613  int mfem_idx = (*lex_ordering)[lex_idx];
614  int vtk_idx = vtk_inv_map[lex_idx];
615  int pt_idx = cell_data[n + vtk_idx];
616  if (pts_dof[pt_idx] == -1)
617  {
618  pts_dof[pt_idx] = dofs[mfem_idx];
619  }
620  else
621  {
622  if (pts_dof[pt_idx] != dofs[mfem_idx])
623  {
624  MFEM_ABORT("VTK mesh: inconsistent Lagrange mesh!");
625  }
626  }
627  }
628  n += dofs.Size();
629  }
630  }
631  // Define the 'Nodes' from the 'points' through the 'pts_dof' map
632  Array<int> dofs;
633  for (int i = 0; i < np; i++)
634  {
635  dofs.SetSize(1);
636  if (pts_dof[i] != -1)
637  {
638  dofs[0] = pts_dof[i];
639  fes->DofsToVDofs(dofs);
640  for (int d = 0; d < dofs.Size(); d++)
641  {
642  (*Nodes)(dofs[d]) = points(3*i+d);
643  }
644  }
645  }
646  read_gf = 0;
647  }
648 }
649 
650 namespace vtk_xml
651 {
652 
653 using namespace tinyxml2;
654 
655 /// Return false if either string is NULL or if the strings differ, return true
656 /// if the strings are the same.
657 bool StringCompare(const char *s1, const char *s2)
658 {
659  if (s1 == NULL || s2 == NULL) { return false; }
660  return strcmp(s1, s2) == 0;
661 }
662 
663 /// Abstract base class for reading continguous arrays of (potentially
664 /// compressed, potentially base-64 encoded) binary data from a buffer into a
665 /// destination array. The types of the source and destination arrays may be
666 /// different (e.g. read data of type uint8_t into destination array of
667 /// uint32_t), which is handled by the templated derived class @a BufferReader.
668 struct BufferReaderBase
669 {
670  enum HeaderType { UINT32_HEADER, UINT64_HEADER };
671  virtual void ReadBinary(const char *buf, void *dest, int n) const = 0;
672  virtual void ReadBase64(const char *txt, void *dest, int n) const = 0;
673  virtual ~BufferReaderBase() { }
674 };
675 
676 /// Read an array of source data stored as (potentially compressed, potentially
677 /// base-64 encoded) into a destination array. The types of the elements in the
678 /// source array are given by template parameter @a F ("from") and the types of
679 /// the elements of the destination array are given by @a T ("to"). The binary
680 /// data has a header, which is one integer if the data is uncompressed, and is
681 /// four integers if the data is compressed. The integers may either by uint32_t
682 /// or uint64_t, according to the @a header_type. If the data is compressed and
683 /// base-64 encoded, then the header is encoded separately from the data. If the
684 /// data is uncompressed and base-64 encoded, then the header and data are
685 /// encoded together.
686 template <typename T, typename F>
687 struct BufferReader : BufferReaderBase
688 {
689  bool compressed;
690  HeaderType header_type;
691  BufferReader(bool compressed_, HeaderType header_type_)
692  : compressed(compressed_), header_type(header_type_) { }
693 
694  /// Return the number of bytes of each header entry.
695  size_t HeaderEntrySize() const
696  {
697  return header_type == UINT64_HEADER ? sizeof(uint64_t) : sizeof(uint32_t);
698  }
699 
700  /// Return the value of the header entry pointer to by @a header_buf. The
701  /// value is stored as either uint32_t or uint64_t, according to the @a
702  /// header_type, and is returned as uint64_t.
703  uint64_t ReadHeaderEntry(const char *header_buf) const
704  {
705  return (header_type == UINT64_HEADER) ? bin_io::read<uint64_t>(header_buf)
706  : bin_io::read<uint32_t>(header_buf);
707  }
708 
709  /// Return the number of bytes in the header. The header consists of one
710  /// integer if the data is uncompressed, and @a N + 3 integers if the data is
711  /// compressed, where @a N is the number of blocks. The integers are either
712  /// 32 or 64 bytes depending on the value of @a header_type. The number of
713  /// blocks is determined by reading the first integer (of type @a
714  /// header_type) pointed to by @a header_buf.
715  int NumHeaderBytes(const char *header_buf) const
716  {
717  if (!compressed) { return HeaderEntrySize(); }
718  return (3 + ReadHeaderEntry(header_buf))*HeaderEntrySize();
719  }
720 
721  /// Read @a n elements of type @a F from the source buffer @a buf into the
722  /// (pre-allocated) destination array of elements of type @a T stored in
723  /// the buffer @a dest_void. The header is stored @b separately from the
724  /// rest of the data, in the buffer @a header_buf. The data buffer @a buf
725  /// does @b not contain a header.
726  void ReadBinaryWithHeader(const char *header_buf, const char *buf,
727  void *dest_void, int n) const
728  {
729  std::vector<char> uncompressed_data;
730  T *dest = static_cast<T*>(dest_void);
731 
732  if (compressed)
733  {
734 #ifdef MFEM_USE_ZLIB
735  // The header has format (where header_t is uint32_t or uint64_t):
736  // header_t number_of_blocks;
737  // header_t uncompressed_block_size;
738  // header_t uncompressed_last_block_size;
739  // header_t compressed_size[number_of_blocks];
740  int header_entry_size = HeaderEntrySize();
741  int nblocks = ReadHeaderEntry(header_buf);
742  header_buf += header_entry_size;
743  std::vector<int> header(nblocks + 2);
744  for (int i=0; i<nblocks+2; ++i)
745  {
746  header[i] = ReadHeaderEntry(header_buf);
747  header_buf += header_entry_size;
748  }
749  uncompressed_data.resize((nblocks-1)*header[0] + header[1]);
750  Bytef *dest_ptr = (Bytef *)uncompressed_data.data();
751  Bytef *dest_start = dest_ptr;
752  const Bytef *source_ptr = (const Bytef *)buf;
753  for (int i=0; i<nblocks; ++i)
754  {
755  uLongf source_len = header[i+2];
756  uLong dest_len = (i == nblocks-1) ? header[1] : header[0];
757  int res = uncompress(dest_ptr, &dest_len, source_ptr, source_len);
758  MFEM_VERIFY(res == Z_OK, "Error uncompressing");
759  dest_ptr += dest_len;
760  source_ptr += source_len;
761  }
762  MFEM_VERIFY(int(sizeof(F)*n) == (dest_ptr - dest_start),
763  "AppendedData: wrong data size");
764  buf = uncompressed_data.data();
765 #else
766  MFEM_ABORT("MFEM must be compiled with zlib enabled to uncompress.")
767 #endif
768  }
769  else
770  {
771  // Each "data block" is preceded by a header that is either UInt32 or
772  // UInt64. The rest of the data follows.
773  uint64_t data_size;
774  if (header_type == UINT32_HEADER)
775  {
776  uint32_t *data_size_32 = (uint32_t *)header_buf;
777  data_size = *data_size_32;
778  }
779  else
780  {
781  uint64_t *data_size_64 = (uint64_t *)header_buf;
782  data_size = *data_size_64;
783  }
784  MFEM_VERIFY(sizeof(F)*n == data_size, "AppendedData: wrong data size");
785  }
786 
787  if (std::is_same<T, F>::value)
788  {
789  // Special case: no type conversions necessary, so can just memcpy
790  memcpy(dest, buf, sizeof(T)*n);
791  }
792  else
793  {
794  for (int i=0; i<n; ++i)
795  {
796  // Read binary data as type F, place in array as type T
797  dest[i] = bin_io::read<F>(buf + i*sizeof(F));
798  }
799  }
800  }
801 
802  /// Read @a n elements of type @a F from source buffer @a buf into
803  /// (pre-allocated) array of elements of type @a T stored in destination
804  /// buffer @a dest. The input buffer contains both the header and the data.
805  void ReadBinary(const char *buf, void *dest, int n) const override
806  {
807  ReadBinaryWithHeader(buf, buf + NumHeaderBytes(buf), dest, n);
808  }
809 
810  /// Read @a n elements of type @a F from base-64 encoded source buffer into
811  /// (pre-allocated) array of elements of type @a T stored in destination
812  /// buffer @a dest. The base-64-encoded data is given by the null-terminated
813  /// string @a txt, which contains both the header and the data.
814  void ReadBase64(const char *txt, void *dest, int n) const override
815  {
816  // Skip whitespace
817  while (*txt)
818  {
819  if (*txt != ' ' && *txt != '\n') { break; }
820  ++txt;
821  }
822  if (compressed)
823  {
824  // Decode the first entry of the header, which we need to determine
825  // how long the rest of the header is.
826  std::vector<char> nblocks_buf;
827  int nblocks_b64 = bin_io::NumBase64Chars(HeaderEntrySize());
828  bin_io::DecodeBase64(txt, nblocks_b64, nblocks_buf);
829  std::vector<char> data, header;
830  // Compute number of characters needed to encode header in base 64,
831  // then round to nearest multiple of 4 to take padding into account.
832  int header_b64 = bin_io::NumBase64Chars(NumHeaderBytes(nblocks_buf.data()));
833  // If data is compressed, header is encoded separately
834  bin_io::DecodeBase64(txt, header_b64, header);
835  bin_io::DecodeBase64(txt + header_b64, strlen(txt)-header_b64, data);
836  ReadBinaryWithHeader(header.data(), data.data(), dest, n);
837  }
838  else
839  {
840  std::vector<char> data;
841  bin_io::DecodeBase64(txt, strlen(txt), data);
842  ReadBinary(data.data(), dest, n);
843  }
844  }
845 };
846 
847 /// Class to read data from VTK's @a DataArary elements. Each @a DataArray can
848 /// contain inline ASCII data, inline base-64-encoded data (potentially
849 /// compressed), or reference "appended data", which may be raw or base-64, and
850 /// may be compressed or uncompressed.
851 struct XMLDataReader
852 {
853  const char *appended_data, *byte_order, *compressor;
854  enum AppendedDataEncoding { RAW, BASE64 };
855  map<string,BufferReaderBase*> type_map;
856  AppendedDataEncoding encoding;
857 
858  /// Create the data reader, where @a vtk is the @a VTKFile XML element, and
859  /// @a vtu is the child @a UnstructuredGrid XML element. This will determine
860  /// the header type (32 or 64 bit integers) and whether compression is
861  /// enabled or not. The appended data will be loaded.
862  XMLDataReader(const XMLElement *vtk, const XMLElement *vtu)
863  {
864  // Determine whether binary data header is 32 or 64 bit integer
865  BufferReaderBase::HeaderType htype;
866  if (StringCompare(vtk->Attribute("header_type"), "UInt64"))
867  {
868  htype = BufferReaderBase::UINT64_HEADER;
869  }
870  else
871  {
872  htype = BufferReaderBase::UINT32_HEADER;
873  }
874 
875  // Get the byte order of the file (will check if we encounter binary data)
876  byte_order = vtk->Attribute("byte_order");
877 
878  // Get the compressor. We will check that MFEM can handle the compression
879  // if we encounter binary data.
880  compressor = vtk->Attribute("compressor");
881  bool compressed = (compressor != NULL);
882 
883  // Find the appended data.
884  appended_data = NULL;
885  for (const XMLElement *xml_elem = vtu->NextSiblingElement();
886  xml_elem != NULL;
887  xml_elem = xml_elem->NextSiblingElement())
888  {
889  if (StringCompare(xml_elem->Name(), "AppendedData"))
890  {
891  const char *encoding_str = xml_elem->Attribute("encoding");
892  if (StringCompare(encoding_str, "raw"))
893  {
894  appended_data = xml_elem->GetAppendedData();
895  encoding = RAW;
896  }
897  else if (StringCompare(encoding_str, "base64"))
898  {
899  appended_data = xml_elem->GetText();
900  encoding = BASE64;
901  }
902  MFEM_VERIFY(appended_data != NULL, "Invalid AppendedData");
903  // Appended data follows first underscore
904  bool found_leading_underscore = false;
905  while (*appended_data)
906  {
907  ++appended_data;
908  if (*appended_data == '_')
909  {
910  found_leading_underscore = true;
911  ++appended_data;
912  break;
913  }
914  }
915  MFEM_VERIFY(found_leading_underscore, "Invalid AppendedData");
916  break;
917  }
918  }
919 
920  type_map["Int8"] = new BufferReader<int, int8_t>(compressed, htype);
921  type_map["Int16"] = new BufferReader<int, int16_t>(compressed, htype);
922  type_map["Int32"] = new BufferReader<int, int32_t>(compressed, htype);
923  type_map["Int64"] = new BufferReader<int, int64_t>(compressed, htype);
924  type_map["UInt8"] = new BufferReader<int, uint8_t>(compressed, htype);
925  type_map["UInt16"] = new BufferReader<int, uint16_t>(compressed, htype);
926  type_map["UInt32"] = new BufferReader<int, uint32_t>(compressed, htype);
927  type_map["UInt64"] = new BufferReader<int, uint64_t>(compressed, htype);
928  type_map["Float32"] = new BufferReader<double, float>(compressed, htype);
929  type_map["Float64"] = new BufferReader<double, double>(compressed, htype);
930  }
931 
932  /// Read the @a DataArray XML element given by @a xml_elem into
933  /// (pre-allocated) destination array @a dest, where @a dest stores @a n
934  /// elements of type @a T.
935  template <typename T>
936  void Read(const XMLElement *xml_elem, T *dest, int n)
937  {
938  static const char *erstr = "Error reading XML DataArray";
939  MFEM_VERIFY(StringCompare(xml_elem->Name(), "DataArray"), erstr);
940  const char *format = xml_elem->Attribute("format");
941  if (StringCompare(format, "ascii"))
942  {
943  const char *txt = xml_elem->GetText();
944  MFEM_VERIFY(txt != NULL, erstr);
945  std::istringstream data_stream(txt);
946  for (int i=0; i<n; ++i) { data_stream >> dest[i]; }
947  }
948  else if (StringCompare(format, "appended"))
949  {
950  VerifyBinaryOptions();
951  int offset = xml_elem->IntAttribute("offset");
952  const char *type = xml_elem->Attribute("type");
953  MFEM_VERIFY(type != NULL, erstr);
954  BufferReaderBase *reader = type_map[type];
955  MFEM_VERIFY(reader != NULL, erstr);
956  MFEM_VERIFY(appended_data != NULL, "No AppendedData found");
957  if (encoding == RAW)
958  {
959  reader->ReadBinary(appended_data + offset, dest, n);
960  }
961  else
962  {
963  reader->ReadBase64(appended_data + offset, dest, n);
964  }
965  }
966  else if (StringCompare(format, "binary"))
967  {
968  VerifyBinaryOptions();
969  const char *txt = xml_elem->GetText();
970  MFEM_VERIFY(txt != NULL, erstr);
971  const char *type = xml_elem->Attribute("type");
972  if (type == NULL) { MFEM_ABORT(erstr); }
973  BufferReaderBase *reader = type_map[type];
974  if (reader == NULL) { MFEM_ABORT(erstr); }
975  reader->ReadBase64(txt, dest, n);
976  }
977  else
978  {
979  MFEM_ABORT("Invalid XML VTK DataArray format");
980  }
981  }
982 
983  /// Check that the byte order of the file is the same as the native byte
984  /// order that we're running with. We don't currently support converting
985  /// between byte orders. The byte order is only verified if we encounter
986  /// binary data.
987  void VerifyByteOrder() const
988  {
989  // Can't handle reading big endian from little endian or vice versa
990  if (byte_order && !StringCompare(byte_order, VTKByteOrder()))
991  {
992  MFEM_ABORT("Converting between different byte orders is unsupported.");
993  }
994  }
995 
996  /// Check that the compressor is compatible (MFEM currently only supports
997  /// zlib compression). If MFEM is not compiled with zlib, then we cannot
998  /// read binary data with compression.
999  void VerifyCompressor() const
1000  {
1001  if (compressor && !StringCompare(compressor, "vtkZLibDataCompressor"))
1002  {
1003  MFEM_ABORT("Unsupported compressor. Only zlib is supported.")
1004  }
1005 #ifndef MFEM_USE_ZLIB
1006  MFEM_VERIFY(compressor == NULL, "MFEM must be compiled with zlib enabled "
1007  "to support reading compressed data.");
1008 #endif
1009  }
1010 
1011  /// Verify that the binary data is stored with compatible options (i.e.
1012  /// native byte order and compatible compression).
1013  void VerifyBinaryOptions() const
1014  {
1015  VerifyByteOrder();
1016  VerifyCompressor();
1017  }
1018 
1019  ~XMLDataReader()
1020  {
1021  for (auto &x : type_map) { delete x.second; }
1022  }
1023 };
1024 
1025 } // namespace vtk_xml
1026 
1027 void Mesh::ReadXML_VTKMesh(std::istream &input, int &curved, int &read_gf,
1028  bool &finalize_topo, const std::string &xml_prefix)
1029 {
1030  using namespace vtk_xml;
1031 
1032  static const char *erstr = "XML parsing error";
1033 
1034  // Create buffer beginning with xml_prefix, then read the rest of the stream
1035  std::vector<char> buf(xml_prefix.begin(), xml_prefix.end());
1036  std::istreambuf_iterator<char> eos;
1037  buf.insert(buf.end(), std::istreambuf_iterator<char>(input), eos);
1038  buf.push_back('\0'); // null-terminate buffer
1039 
1040  XMLDocument xml;
1041  xml.Parse(buf.data(), buf.size());
1042  if (xml.ErrorID() != XML_SUCCESS)
1043  {
1044  MFEM_ABORT("Error parsing XML VTK file.\n" << xml.ErrorStr());
1045  }
1046 
1047  const XMLElement *vtkfile = xml.FirstChildElement();
1048  MFEM_VERIFY(vtkfile, erstr);
1049  MFEM_VERIFY(StringCompare(vtkfile->Name(), "VTKFile"), erstr);
1050  const XMLElement *vtu = vtkfile->FirstChildElement();
1051  MFEM_VERIFY(vtu, erstr);
1052  MFEM_VERIFY(StringCompare(vtu->Name(), "UnstructuredGrid"), erstr);
1053 
1054  XMLDataReader data_reader(vtkfile, vtu);
1055 
1056  // Count the number of points and cells
1057  const XMLElement *piece = vtu->FirstChildElement();
1058  MFEM_VERIFY(StringCompare(piece->Name(), "Piece"), erstr);
1059  MFEM_VERIFY(piece->NextSiblingElement() == NULL,
1060  "XML VTK meshes with more than one Piece are not supported");
1061  int npts = piece->IntAttribute("NumberOfPoints");
1062  int ncells = piece->IntAttribute("NumberOfCells");
1063 
1064  // Read the points
1065  Vector points(3*npts);
1066  const XMLElement *pts_xml;
1067  for (pts_xml = piece->FirstChildElement();
1068  pts_xml != NULL;
1069  pts_xml = pts_xml->NextSiblingElement())
1070  {
1071  if (StringCompare(pts_xml->Name(), "Points"))
1072  {
1073  const XMLElement *pts_data = pts_xml->FirstChildElement();
1074  MFEM_VERIFY(pts_data->IntAttribute("NumberOfComponents") == 3,
1075  "XML VTK Points DataArray must have 3 components");
1076  data_reader.Read(pts_data, points.GetData(), points.Size());
1077  break;
1078  }
1079  }
1080  if (pts_xml == NULL) { MFEM_ABORT(erstr); }
1081 
1082  // Read the cells
1083  Array<int> cell_data, cell_offsets(ncells), cell_types(ncells);
1084  const XMLElement *cells_xml;
1085  for (cells_xml = piece->FirstChildElement();
1086  cells_xml != NULL;
1087  cells_xml = cells_xml->NextSiblingElement())
1088  {
1089  if (StringCompare(cells_xml->Name(), "Cells"))
1090  {
1091  const XMLElement *cell_data_xml = NULL;
1092  for (const XMLElement *data_xml = cells_xml->FirstChildElement();
1093  data_xml != NULL;
1094  data_xml = data_xml->NextSiblingElement())
1095  {
1096  const char *data_name = data_xml->Attribute("Name");
1097  if (StringCompare(data_name, "offsets"))
1098  {
1099  data_reader.Read(data_xml, cell_offsets.GetData(), ncells);
1100  }
1101  else if (StringCompare(data_name, "types"))
1102  {
1103  data_reader.Read(data_xml, cell_types.GetData(), ncells);
1104  }
1105  else if (StringCompare(data_name, "connectivity"))
1106  {
1107  // Have to read the connectivity after the offsets, because we
1108  // don't know how many points to read until we have the offsets
1109  // (size of connectivity array is equal to the last offset), so
1110  // store the XML element pointer and read this data later.
1111  cell_data_xml = data_xml;
1112  }
1113  }
1114  MFEM_VERIFY(cell_data_xml != NULL, erstr);
1115  int cell_data_size = cell_offsets.Last();
1116  cell_data.SetSize(cell_data_size);
1117  data_reader.Read(cell_data_xml, cell_data.GetData(), cell_data_size);
1118  break;
1119  }
1120  }
1121  if (cells_xml == NULL) { MFEM_ABORT(erstr); }
1122 
1123  // Read the element attributes, which are stored as CellData named "material"
1124  Array<int> cell_attributes;
1125  for (const XMLElement *cell_data_xml = piece->FirstChildElement();
1126  cell_data_xml != NULL;
1127  cell_data_xml = cell_data_xml->NextSiblingElement())
1128  {
1129  if (StringCompare(cell_data_xml->Name(), "CellData")
1130  && StringCompare(cell_data_xml->Attribute("Scalars"), "material"))
1131  {
1132  const XMLElement *data_xml = cell_data_xml->FirstChildElement();
1133  if (data_xml != NULL && StringCompare(data_xml->Name(), "DataArray"))
1134  {
1135  cell_attributes.SetSize(ncells);
1136  data_reader.Read(data_xml, cell_attributes.GetData(), ncells);
1137  }
1138  }
1139  }
1140 
1141  CreateVTKMesh(points, cell_data, cell_offsets, cell_types, cell_attributes,
1142  curved, read_gf, finalize_topo);
1143 }
1144 
1145 void Mesh::ReadVTKMesh(std::istream &input, int &curved, int &read_gf,
1146  bool &finalize_topo)
1147 {
1148  // VTK resources:
1149  // * https://www.vtk.org/doc/nightly/html/vtkCellType_8h_source.html
1150  // * https://www.vtk.org/doc/nightly/html/classvtkCell.html
1151  // * https://lorensen.github.io/VTKExamples/site/VTKFileFormats
1152  // * https://www.kitware.com/products/books/VTKUsersGuide.pdf
1153 
1154  string buff;
1155  getline(input, buff); // comment line
1156  getline(input, buff);
1157  filter_dos(buff);
1158  if (buff != "ASCII")
1159  {
1160  MFEM_ABORT("VTK mesh is not in ASCII format!");
1161  return;
1162  }
1163  do
1164  {
1165  getline(input, buff);
1166  filter_dos(buff);
1167  if (!input.good()) { MFEM_ABORT("VTK mesh is not UNSTRUCTURED_GRID!"); }
1168  }
1169  while (buff != "DATASET UNSTRUCTURED_GRID");
1170 
1171  // Read the points, skipping optional sections such as the FIELD data from
1172  // VisIt's VTK export (or from Mesh::PrintVTK with field_data==1).
1173  do
1174  {
1175  input >> buff;
1176  if (!input.good())
1177  {
1178  MFEM_ABORT("VTK mesh does not have POINTS data!");
1179  }
1180  }
1181  while (buff != "POINTS");
1182 
1183  Vector points;
1184  int np;
1185  input >> np >> ws;
1186  getline(input, buff); // "double"
1187  points.Load(input, 3*np);
1188 
1189  //skip metadata
1190  // Looks like:
1191  // METADATA
1192  //INFORMATION 2
1193  //NAME L2_NORM_RANGE LOCATION vtkDataArray
1194  //DATA 2 0 5.19615
1195  //NAME L2_NORM_FINITE_RANGE LOCATION vtkDataArray
1196  //DATA 2 0 5.19615
1197  do
1198  {
1199  input >> buff;
1200  if (!input.good())
1201  {
1202  MFEM_ABORT("VTK mesh does not have CELLS data!");
1203  }
1204  }
1205  while (buff != "CELLS");
1206 
1207  // Read the cells
1208  Array<int> cell_data, cell_offsets;
1209  if (buff == "CELLS")
1210  {
1211  int ncells, n;
1212  input >> ncells >> n >> ws;
1213  cell_offsets.SetSize(ncells);
1214  cell_data.SetSize(n - ncells);
1215  int offset = 0;
1216  for (int i=0; i<ncells; ++i)
1217  {
1218  int nv;
1219  input >> nv;
1220  cell_offsets[i] = offset + nv;
1221  for (int j=0; j<nv; ++j)
1222  {
1223  input >> cell_data[offset + j];
1224  }
1225  offset += nv;
1226  }
1227  }
1228 
1229  // Read the cell types
1230  input >> ws >> buff;
1231  Array<int> cell_types;
1232  int ncells;
1233  MFEM_VERIFY(buff == "CELL_TYPES", "CELL_TYPES not provided in VTK mesh.")
1234  input >> ncells;
1235  cell_types.Load(ncells, input);
1236 
1237  while ((input.good()) && (buff != "CELL_DATA"))
1238  {
1239  input >> buff;
1240  }
1241  getline(input, buff); // finish the line
1242 
1243  // Read the cell materials
1244  // bool found_material = false;
1245  Array<int> cell_attributes;
1246  while ((input.good()))
1247  {
1248  getline(input, buff);
1249  if (buff.rfind("POINT_DATA") == 0)
1250  {
1251  break; // We have entered the POINT_DATA block. Quit.
1252  }
1253  else if (buff.rfind("SCALARS material") == 0)
1254  {
1255  getline(input, buff); // LOOKUP_TABLE default
1256  if (buff.rfind("LOOKUP_TABLE default") != 0)
1257  {
1258  MFEM_ABORT("Invalid LOOKUP_TABLE for material array in VTK file.");
1259  }
1260  cell_attributes.Load(ncells, input);
1261  // found_material = true;
1262  break;
1263  }
1264  }
1265 
1266  // if (!found_material)
1267  // {
1268  // MFEM_WARNING("Material array not found in VTK file. "
1269  // "Assuming uniform material composition.");
1270  // }
1271 
1272  CreateVTKMesh(points, cell_data, cell_offsets, cell_types, cell_attributes,
1273  curved, read_gf, finalize_topo);
1274 } // end ReadVTKMesh
1275 
1276 void Mesh::ReadNURBSMesh(std::istream &input, int &curved, int &read_gf)
1277 {
1278  NURBSext = new NURBSExtension(input);
1279 
1280  Dim = NURBSext->Dimension();
1281  NumOfVertices = NURBSext->GetNV();
1282  NumOfElements = NURBSext->GetNE();
1283  NumOfBdrElements = NURBSext->GetNBE();
1284 
1285  NURBSext->GetElementTopo(elements);
1286  NURBSext->GetBdrElementTopo(boundary);
1287 
1288  vertices.SetSize(NumOfVertices);
1289  curved = 1;
1290  if (NURBSext->HavePatches())
1291  {
1292  NURBSFECollection *fec = new NURBSFECollection(NURBSext->GetOrder());
1293  FiniteElementSpace *fes = new FiniteElementSpace(this, fec, Dim,
1294  Ordering::byVDIM);
1295  Nodes = new GridFunction(fes);
1296  Nodes->MakeOwner(fec);
1297  NURBSext->SetCoordsFromPatches(*Nodes);
1298  own_nodes = 1;
1299  read_gf = 0;
1300  spaceDim = Nodes->VectorDim();
1301  for (int i = 0; i < spaceDim; i++)
1302  {
1303  Vector vert_val;
1304  Nodes->GetNodalValues(vert_val, i+1);
1305  for (int j = 0; j < NumOfVertices; j++)
1306  {
1307  vertices[j](i) = vert_val(j);
1308  }
1309  }
1310  }
1311  else
1312  {
1313  read_gf = 1;
1314  }
1315 }
1316 
1317 void Mesh::ReadInlineMesh(std::istream &input, bool generate_edges)
1318 {
1319  // Initialize to negative numbers so that we know if they've been set. We're
1320  // using Element::POINT as our flag, since we're not going to make a 0D mesh,
1321  // ever.
1322  int nx = -1;
1323  int ny = -1;
1324  int nz = -1;
1325  double sx = -1.0;
1326  double sy = -1.0;
1327  double sz = -1.0;
1328  Element::Type type = Element::POINT;
1329 
1330  while (true)
1331  {
1332  skip_comment_lines(input, '#');
1333  // Break out if we reached the end of the file after gobbling up the
1334  // whitespace and comments after the last keyword.
1335  if (!input.good())
1336  {
1337  break;
1338  }
1339 
1340  // Read the next keyword
1341  std::string name;
1342  input >> name;
1343  input >> std::ws;
1344  // Make sure there's an equal sign
1345  MFEM_VERIFY(input.get() == '=',
1346  "Inline mesh expected '=' after keyword " << name);
1347  input >> std::ws;
1348 
1349  if (name == "nx")
1350  {
1351  input >> nx;
1352  }
1353  else if (name == "ny")
1354  {
1355  input >> ny;
1356  }
1357  else if (name == "nz")
1358  {
1359  input >> nz;
1360  }
1361  else if (name == "sx")
1362  {
1363  input >> sx;
1364  }
1365  else if (name == "sy")
1366  {
1367  input >> sy;
1368  }
1369  else if (name == "sz")
1370  {
1371  input >> sz;
1372  }
1373  else if (name == "type")
1374  {
1375  std::string eltype;
1376  input >> eltype;
1377  if (eltype == "segment")
1378  {
1379  type = Element::SEGMENT;
1380  }
1381  else if (eltype == "quad")
1382  {
1383  type = Element::QUADRILATERAL;
1384  }
1385  else if (eltype == "tri")
1386  {
1387  type = Element::TRIANGLE;
1388  }
1389  else if (eltype == "hex")
1390  {
1391  type = Element::HEXAHEDRON;
1392  }
1393  else if (eltype == "wedge")
1394  {
1395  type = Element::WEDGE;
1396  }
1397  else if (eltype == "tet")
1398  {
1399  type = Element::TETRAHEDRON;
1400  }
1401  else
1402  {
1403  MFEM_ABORT("unrecognized element type (read '" << eltype
1404  << "') in inline mesh format. "
1405  "Allowed: segment, tri, quad, tet, hex, wedge");
1406  }
1407  }
1408  else
1409  {
1410  MFEM_ABORT("unrecognized keyword (" << name
1411  << ") in inline mesh format. "
1412  "Allowed: nx, ny, nz, type, sx, sy, sz");
1413  }
1414 
1415  input >> std::ws;
1416  // Allow an optional semi-colon at the end of each line.
1417  if (input.peek() == ';')
1418  {
1419  input.get();
1420  }
1421 
1422  // Done reading file
1423  if (!input)
1424  {
1425  break;
1426  }
1427  }
1428 
1429  // Now make the mesh.
1430  if (type == Element::SEGMENT)
1431  {
1432  MFEM_VERIFY(nx > 0 && sx > 0.0,
1433  "invalid 1D inline mesh format, all values must be "
1434  "positive\n"
1435  << " nx = " << nx << "\n"
1436  << " sx = " << sx << "\n");
1437  Make1D(nx, sx);
1438  }
1439  else if (type == Element::TRIANGLE || type == Element::QUADRILATERAL)
1440  {
1441  MFEM_VERIFY(nx > 0 && ny > 0 && sx > 0.0 && sy > 0.0,
1442  "invalid 2D inline mesh format, all values must be "
1443  "positive\n"
1444  << " nx = " << nx << "\n"
1445  << " ny = " << ny << "\n"
1446  << " sx = " << sx << "\n"
1447  << " sy = " << sy << "\n");
1448  Make2D(nx, ny, type, sx, sy, generate_edges, true);
1449  }
1450  else if (type == Element::TETRAHEDRON || type == Element::WEDGE ||
1451  type == Element::HEXAHEDRON)
1452  {
1453  MFEM_VERIFY(nx > 0 && ny > 0 && nz > 0 &&
1454  sx > 0.0 && sy > 0.0 && sz > 0.0,
1455  "invalid 3D inline mesh format, all values must be "
1456  "positive\n"
1457  << " nx = " << nx << "\n"
1458  << " ny = " << ny << "\n"
1459  << " nz = " << nz << "\n"
1460  << " sx = " << sx << "\n"
1461  << " sy = " << sy << "\n"
1462  << " sz = " << sz << "\n");
1463  Make3D(nx, ny, nz, type, sx, sy, sz, true);
1464  // TODO: maybe have an option in the file to control ordering?
1465  }
1466  else
1467  {
1468  MFEM_ABORT("For inline mesh, must specify an element type ="
1469  " [segment, tri, quad, tet, hex, wedge]");
1470  }
1471 }
1472 
1473 void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
1474 {
1475  string buff;
1476  double version;
1477  int binary, dsize;
1478  input >> version >> binary >> dsize;
1479  if (version < 2.2)
1480  {
1481  MFEM_ABORT("Gmsh file version < 2.2");
1482  }
1483  if (dsize != sizeof(double))
1484  {
1485  MFEM_ABORT("Gmsh file : dsize != sizeof(double)");
1486  }
1487  getline(input, buff);
1488  // There is a number 1 in binary format
1489  if (binary)
1490  {
1491  int one;
1492  input.read(reinterpret_cast<char*>(&one), sizeof(one));
1493  if (one != 1)
1494  {
1495  MFEM_ABORT("Gmsh file : wrong binary format");
1496  }
1497  }
1498 
1499  // A map between a serial number of the vertex and its number in the file
1500  // (there may be gaps in the numbering, and also Gmsh enumerates vertices
1501  // starting from 1, not 0)
1502  map<int, int> vertices_map;
1503 
1504  // Gmsh always outputs coordinates in 3D, but MFEM distinguishes between the
1505  // mesh element dimension (Dim) and the dimension of the space in which the
1506  // mesh is embedded (spaceDim). For example, a 2D MFEM mesh has Dim = 2 and
1507  // spaceDim = 2, while a 2D surface mesh in 3D has Dim = 2 but spaceDim = 3.
1508  // Below we set spaceDim by measuring the mesh bounding box and checking for
1509  // a lower dimensional subspace. The assumption is that the mesh is at least
1510  // 2D if the y-dimension of the box is non-trivial and 3D if the z-dimension
1511  // is non-trivial. Note that with these assumptions a 2D mesh parallel to the
1512  // yz plane will be considered a surface mesh embedded in 3D whereas the same
1513  // 2D mesh parallel to the xy plane will be considered a 2D mesh.
1514  double bb_tol = 1e-14;
1515  double bb_min[3];
1516  double bb_max[3];
1517 
1518  // Mesh order
1519  int mesh_order = 1;
1520 
1521  // Mesh type
1522  bool periodic = false;
1523 
1524  // Vector field to store uniformly spaced Gmsh high order mesh coords
1525  GridFunction Nodes_gf;
1526 
1527  // Read the lines of the mesh file. If we face specific keyword, we'll treat
1528  // the section.
1529  while (input >> buff)
1530  {
1531  if (buff == "$Nodes") // reading mesh vertices
1532  {
1533  input >> NumOfVertices;
1534  getline(input, buff);
1535  vertices.SetSize(NumOfVertices);
1536  int serial_number;
1537  const int gmsh_dim = 3; // Gmsh always outputs 3 coordinates
1538  double coord[gmsh_dim];
1539  for (int ver = 0; ver < NumOfVertices; ++ver)
1540  {
1541  if (binary)
1542  {
1543  input.read(reinterpret_cast<char*>(&serial_number), sizeof(int));
1544  input.read(reinterpret_cast<char*>(coord), gmsh_dim*sizeof(double));
1545  }
1546  else // ASCII
1547  {
1548  input >> serial_number;
1549  for (int ci = 0; ci < gmsh_dim; ++ci)
1550  {
1551  input >> coord[ci];
1552  }
1553  }
1554  vertices[ver] = Vertex(coord, gmsh_dim);
1555  vertices_map[serial_number] = ver;
1556 
1557  for (int ci = 0; ci < gmsh_dim; ++ci)
1558  {
1559  bb_min[ci] = (ver == 0) ? coord[ci] :
1560  std::min(bb_min[ci], coord[ci]);
1561  bb_max[ci] = (ver == 0) ? coord[ci] :
1562  std::max(bb_max[ci], coord[ci]);
1563  }
1564  }
1565  double bb_size = std::max(bb_max[0] - bb_min[0],
1566  std::max(bb_max[1] - bb_min[1],
1567  bb_max[2] - bb_min[2]));
1568  spaceDim = 1;
1569  if (bb_max[1] - bb_min[1] > bb_size * bb_tol)
1570  {
1571  spaceDim++;
1572  }
1573  if (bb_max[2] - bb_min[2] > bb_size * bb_tol)
1574  {
1575  spaceDim++;
1576  }
1577 
1578  if (static_cast<int>(vertices_map.size()) != NumOfVertices)
1579  {
1580  MFEM_ABORT("Gmsh file : vertices indices are not unique");
1581  }
1582  } // section '$Nodes'
1583  else if (buff == "$Elements") // reading mesh elements
1584  {
1585  int num_of_all_elements;
1586  input >> num_of_all_elements;
1587  // = NumOfElements + NumOfBdrElements + (maybe, PhysicalPoints)
1588  getline(input, buff);
1589 
1590  int serial_number; // serial number of an element
1591  int type_of_element; // ID describing a type of a mesh element
1592  int n_tags; // number of different tags describing an element
1593  int phys_domain; // element's attribute
1594  int elem_domain; // another element's attribute (rarely used)
1595  int n_partitions; // number of partitions where an element takes place
1596 
1597  // number of nodes for each type of Gmsh elements, type is the index of
1598  // the array + 1
1599  int nodes_of_gmsh_element[] =
1600  {
1601  2, // 2-node line.
1602  3, // 3-node triangle.
1603  4, // 4-node quadrangle.
1604  4, // 4-node tetrahedron.
1605  8, // 8-node hexahedron.
1606  6, // 6-node prism.
1607  5, // 5-node pyramid.
1608  3, /* 3-node second order line (2 nodes associated with the
1609  vertices and 1 with the edge). */
1610  6, /* 6-node second order triangle (3 nodes associated with the
1611  vertices and 3 with the edges). */
1612  9, /* 9-node second order quadrangle (4 nodes associated with the
1613  vertices, 4 with the edges and 1 with the face). */
1614  10, /* 10-node second order tetrahedron (4 nodes associated with
1615  the vertices and 6 with the edges). */
1616  27, /* 27-node second order hexahedron (8 nodes associated with the
1617  vertices, 12 with the edges, 6 with the faces and 1 with the
1618  volume). */
1619  18, /* 18-node second order prism (6 nodes associated with the
1620  vertices, 9 with the edges and 3 with the quadrangular
1621  faces). */
1622  14, /* 14-node second order pyramid (5 nodes associated with the
1623  vertices, 8 with the edges and 1 with the quadrangular
1624  face). */
1625  1, // 1-node point.
1626  8, /* 8-node second order quadrangle (4 nodes associated with the
1627  vertices and 4 with the edges). */
1628  20, /* 20-node second order hexahedron (8 nodes associated with the
1629  vertices and 12 with the edges). */
1630  15, /* 15-node second order prism (6 nodes associated with the
1631  vertices and 9 with the edges). */
1632  13, /* 13-node second order pyramid (5 nodes associated with the
1633  vertices and 8 with the edges). */
1634  9, /* 9-node third order incomplete triangle (3 nodes associated
1635  with the vertices, 6 with the edges) */
1636  10, /* 10-node third order triangle (3 nodes associated with the
1637  vertices, 6 with the edges, 1 with the face) */
1638  12, /* 12-node fourth order incomplete triangle (3 nodes associated
1639  with the vertices, 9 with the edges) */
1640  15, /* 15-node fourth order triangle (3 nodes associated with the
1641  vertices, 9 with the edges, 3 with the face) */
1642  15, /* 15-node fifth order incomplete triangle (3 nodes associated
1643  with the vertices, 12 with the edges) */
1644  21, /* 21-node fifth order complete triangle (3 nodes associated
1645  with the vertices, 12 with the edges, 6 with the face) */
1646  4, /* 4-node third order edge (2 nodes associated with the
1647  vertices, 2 internal to the edge) */
1648  5, /* 5-node fourth order edge (2 nodes associated with the
1649  vertices, 3 internal to the edge) */
1650  6, /* 6-node fifth order edge (2 nodes associated with the
1651  vertices, 4 internal to the edge) */
1652  20, /* 20-node third order tetrahedron (4 nodes associated with the
1653  vertices, 12 with the edges, 4 with the faces) */
1654  35, /* 35-node fourth order tetrahedron (4 nodes associated with
1655  the vertices, 18 with the edges, 12 with the faces, and 1
1656  with the volume) */
1657  56, /* 56-node fifth order tetrahedron (4 nodes associated with the
1658  vertices, 24 with the edges, 24 with the faces, and 4 with
1659  the volume) */
1660  -1,-1, /* unsupported tetrahedral types */
1661  -1,-1, /* unsupported polygonal and polyhedral types */
1662  16, /* 16-node third order quadrilateral (4 nodes associated with
1663  the vertices, 8 with the edges, 4 wth the face) */
1664  25, /* 25-node fourth order quadrilateral (4 nodes associated with
1665  the vertices, 12 with the edges, 9 wth the face) */
1666  36, /* 36-node fifth order quadrilateral (4 nodes associated with
1667  the vertices, 16 with the edges, 16 wth the face) */
1668  -1,-1,-1, /* unsupported quadrilateral types */
1669  28, /* 28-node sixth order complete triangle (3 nodes associated
1670  with the vertices, 15 with the edges, 10 with the face) */
1671  36, /* 36-node seventh order complete triangle (3 nodes associated
1672  with the vertices, 18 with the edges, 15 with the face) */
1673  45, /* 45-node eighth order complete triangle (3 nodes associated
1674  with the vertices, 21 with the edges, 21 with the face) */
1675  55, /* 55-node ninth order complete triangle (3 nodes associated
1676  with the vertices, 24 with the edges, 28 with the face) */
1677  66, /* 66-node tenth order complete triangle (3 nodes associated
1678  with the vertices, 27 with the edges, 36 with the face) */
1679  49, /* 49-node sixth order quadrilateral (4 nodes associated with
1680  the vertices, 20 with the edges, 25 wth the face) */
1681  64, /* 64-node seventh order quadrilateral (4 nodes associated with
1682  the vertices, 24 with the edges, 36 wth the face) */
1683  81, /* 81-node eighth order quadrilateral (4 nodes associated with
1684  the vertices, 28 with the edges, 49 wth the face) */
1685  100, /* 100-node ninth order quadrilateral (4 nodes associated with
1686  the vertices, 32 with the edges, 64 wth the face) */
1687  121, /* 121-node tenth order quadrilateral (4 nodes associated with
1688  the vertices, 36 with the edges, 81 wth the face) */
1689  -1,-1,-1,-1,-1, /* unsupported triangular types */
1690  -1,-1,-1,-1,-1, /* unsupported quadrilateral types */
1691  7, /* 7-node sixth order edge (2 nodes associated with the
1692  vertices, 5 internal to the edge) */
1693  8, /* 8-node seventh order edge (2 nodes associated with the
1694  vertices, 6 internal to the edge) */
1695  9, /* 9-node eighth order edge (2 nodes associated with the
1696  vertices, 7 internal to the edge) */
1697  10, /* 10-node ninth order edge (2 nodes associated with the
1698  vertices, 8 internal to the edge) */
1699  11, /* 11-node tenth order edge (2 nodes associated with the
1700  vertices, 9 internal to the edge) */
1701  -1, /* unsupported linear types */
1702  -1,-1,-1, /* unsupported types */
1703  84, /* 84-node sixth order tetrahedron (4 nodes associated with the
1704  vertices, 30 with the edges, 40 with the faces, and 10 with
1705  the volume) */
1706  120, /* 120-node seventh order tetrahedron (4 nodes associated with
1707  the vertices, 36 with the edges, 60 with the faces, and 20
1708  with the volume) */
1709  165, /* 165-node eighth order tetrahedron (4 nodes associated with
1710  the vertices, 42 with the edges, 84 with the faces, and 35
1711  with the volume) */
1712  220, /* 220-node ninth order tetrahedron (4 nodes associated with
1713  the vertices, 48 with the edges, 112 with the faces, and 56
1714  with the volume) */
1715  286, /* 286-node tenth order tetrahedron (4 nodes associated with
1716  the vertices, 54 with the edges, 144 with the faces, and 84
1717  with the volume) */
1718  -1,-1,-1, /* undefined types */
1719  -1,-1,-1,-1,-1, /* unsupported tetrahedral types */
1720  -1,-1,-1,-1,-1,-1, /* unsupported types */
1721  40, /* 40-node third order prism (6 nodes associated with the
1722  vertices, 18 with the edges, 14 with the faces, and 2 with
1723  the volume) */
1724  75, /* 75-node fourth order prism (6 nodes associated with the
1725  vertices, 27 with the edges, 33 with the faces, and 9 with
1726  the volume) */
1727  64, /* 64-node third order hexahedron (8 nodes associated with the
1728  vertices, 24 with the edges, 24 with the faces and 8 with
1729  the volume).*/
1730  125, /* 125-node fourth order hexahedron (8 nodes associated with
1731  the vertices, 36 with the edges, 54 with the faces and 27
1732  with the volume).*/
1733  216, /* 216-node fifth order hexahedron (8 nodes associated with the
1734  vertices, 48 with the edges, 96 with the faces and 64 with
1735  the volume).*/
1736  343, /* 343-node sixth order hexahedron (8 nodes associated with the
1737  vertices, 60 with the edges, 150 with the faces and 125 with
1738  the volume).*/
1739  512, /* 512-node seventh order hexahedron (8 nodes associated with
1740  the vertices, 72 with the edges, 216 with the faces and 216
1741  with the volume).*/
1742  729, /* 729-node eighth order hexahedron (8 nodes associated with
1743  the vertices, 84 with the edges, 294 with the faces and 343
1744  with the volume).*/
1745  1000,/* 1000-node ninth order hexahedron (8 nodes associated with
1746  the vertices, 96 with the edges, 384 with the faces and 512
1747  with the volume).*/
1748  -1,-1,-1,-1,-1,-1,-1, /* unsupported hexahedron types */
1749  126, /* 126-node fifth order prism (6 nodes associated with the
1750  vertices, 36 with the edges, 60 with the faces, and 24 with
1751  the volume) */
1752  196, /* 196-node sixth order prism (6 nodes associated with the
1753  vertices, 45 with the edges, 95 with the faces, and 50 with
1754  the volume) */
1755  288, /* 288-node seventh order prism (6 nodes associated with the
1756  vertices, 54 with the edges, 138 with the faces, and 90 with
1757  the volume) */
1758  405, /* 405-node eighth order prism (6 nodes associated with the
1759  vertices, 63 with the edges, 189 with the faces, and 147
1760  with the volume) */
1761  550, /* 550-node ninth order prism (6 nodes associated with the
1762  vertices, 72 with the edges, 248 with the faces, and 224
1763  with the volume) */
1764  -1,-1,-1,-1,-1,-1,-1, /* unsupported prism types */
1765  30, /* 30-node third order pyramid (5 nodes associated with the
1766  vertices, 16 with the edges and 8 with the faces, and 1 with
1767  the volume). */
1768  55, /* 55-node fourth order pyramid (5 nodes associated with the
1769  vertices, 24 with the edges and 21 with the faces, and 5
1770  with the volume). */
1771  91, /* 91-node fifth order pyramid (5 nodes associated with the
1772  vertices, 32 with the edges and 40 with the faces, and 14
1773  with the volume). */
1774  140, /* 140-node sixth order pyramid (5 nodes associated with the
1775  vertices, 40 with the edges and 65 with the faces, and 30
1776  with the volume). */
1777  204, /* 204-node seventh order pyramid (5 nodes associated with the
1778  vertices, 48 with the edges and 96 with the faces, and 55
1779  with the volume). */
1780  285, /* 285-node eighth order pyramid (5 nodes associated with the
1781  vertices, 56 with the edges and 133 with the faces, and 91
1782  with the volume). */
1783  385 /* 385-node ninth order pyramid (5 nodes associated with the
1784  vertices, 64 with the edges and 176 with the faces, and 140
1785  with the volume). */
1786  };
1787 
1788  /** The following mappings convert the Gmsh node orderings for high
1789  order elements to MFEM's L2 degree of freedom ordering. To support
1790  more options examine Gmsh's ordering and read off the indices in
1791  MFEM's order. For example 2nd order Gmsh quadrilaterals use the
1792  following ordering:
1793 
1794  3--6--2
1795  | | |
1796  7 8 5
1797  | | |
1798  0--4--1
1799 
1800  (from https://gmsh.info/doc/texinfo/gmsh.html#Node-ordering)
1801 
1802  Whereas MFEM uses a tensor product ordering with the horizontal
1803  axis cycling fastest so we would read off:
1804 
1805  0 4 1 7 8 5 3 6 2
1806 
1807  This corresponds to the quad9 mapping below.
1808  */
1809  int lin3[] = {0,2,1}; // 2nd order segment
1810  int lin4[] = {0,2,3,1}; // 3rd order segment
1811  int tri6[] = {0,3,1,5,4,2}; // 2nd order triangle
1812  int tri10[] = {0,3,4,1,8,9,5,7,6,2}; // 3rd order triangle
1813  int quad9[] = {0,4,1,7,8,5,3,6,2}; // 2nd order quadrilateral
1814  int quad16[] = {0,4,5,1,11,12,13,6, // 3rd order quadrilateral
1815  10,15,14,7,3,9,8,2
1816  };
1817  int tet10[] {0,4,1,6,5,2,7,9,8,3}; // 2nd order tetrahedron
1818  int tet20[] = {0,4,5,1,9,16,6,8,7,2, // 3rd order tetrahedron
1819  11,17,15,18,19,13,10,14,12,3
1820  };
1821  int hex27[] {0,8,1,9,20,11,3,13,2, // 2nd order hexahedron
1822  10,21,12,22,26,23,15,24,14,
1823  4,16,5,17,25,18,7,19,6
1824  };
1825  int hex64[] {0,8,9,1,10,32,35,14, // 3rd order hexahedron
1826  11,33,34,15,3,19,18,2,
1827  12,36,37,16,40,56,57,44,
1828  43,59,58,45,22,49,48,20,
1829  13,39,38,17,41,60,61,47,
1830  42,63,62,46,23,50,51,21,
1831  4,24,25,5,26,52,53,28,
1832  27,55,54,29,7,31,30,6
1833  };
1834 
1835  int wdg18[] = {0,6,1,7,9,2,8,15,10, // 2nd order wedge/prism
1836  16,17,11,3,12,4,13,14,5
1837  };
1838  int wdg40[] = {0,6,7,1,8,24,12,9,13,2, // 3rd order wedge/prism
1839  10,26,27,14,30,38,34,33,35,16,
1840  11,29,28,15,31,39,37,32,36,17,
1841  3,18,19,4,20,25,22,21,23,5
1842  };
1843 
1844  int pyr14[] = {0,5,1,6,13,8,3, // 2nd order pyramid
1845  10,2,7,9,12,11,4
1846  };
1847  int pyr30[] = {0,5,6,1,7,25,28,11,8,26, // 3rd order pyramid
1848  27,12,3,16,15,2,9,21,13,22,
1849  29,23,19,24,17,10,14,20,18,4
1850  };
1851 
1852  vector<Element*> elements_0D, elements_1D, elements_2D, elements_3D;
1853  elements_0D.reserve(num_of_all_elements);
1854  elements_1D.reserve(num_of_all_elements);
1855  elements_2D.reserve(num_of_all_elements);
1856  elements_3D.reserve(num_of_all_elements);
1857 
1858  // Temporary storage for high order vertices, if present
1859  vector<Array<int>*> ho_verts_1D, ho_verts_2D, ho_verts_3D;
1860  ho_verts_1D.reserve(num_of_all_elements);
1861  ho_verts_2D.reserve(num_of_all_elements);
1862  ho_verts_3D.reserve(num_of_all_elements);
1863 
1864  // Temporary storage for order of elements
1865  vector<int> ho_el_order_1D, ho_el_order_2D, ho_el_order_3D;
1866  ho_el_order_1D.reserve(num_of_all_elements);
1867  ho_el_order_2D.reserve(num_of_all_elements);
1868  ho_el_order_3D.reserve(num_of_all_elements);
1869 
1870  // Vertex order mappings
1871  Array<int*> ho_lin(11); ho_lin = NULL;
1872  Array<int*> ho_tri(11); ho_tri = NULL;
1873  Array<int*> ho_sqr(11); ho_sqr = NULL;
1874  Array<int*> ho_tet(11); ho_tet = NULL;
1875  Array<int*> ho_hex(10); ho_hex = NULL;
1876  Array<int*> ho_wdg(10); ho_wdg = NULL;
1877  Array<int*> ho_pyr(10); ho_pyr = NULL;
1878 
1879  // Use predefined arrays at lowest orders (for efficiency)
1880  ho_lin[2] = lin3; ho_lin[3] = lin4;
1881  ho_tri[2] = tri6; ho_tri[3] = tri10;
1882  ho_sqr[2] = quad9; ho_sqr[3] = quad16;
1883  ho_tet[2] = tet10; ho_tet[3] = tet20;
1884  ho_hex[2] = hex27; ho_hex[3] = hex64;
1885  ho_wdg[2] = wdg18; ho_wdg[3] = wdg40;
1886  ho_pyr[2] = pyr14; ho_pyr[3] = pyr30;
1887 
1888  if (binary)
1889  {
1890  int n_elem_part = 0; // partial sum of elements that are read
1891  const int header_size = 3;
1892  // header consists of 3 numbers: type of the element, number of
1893  // elements of this type, and number of tags
1894  int header[header_size];
1895  int n_elem_one_type; // number of elements of a specific type
1896 
1897  while (n_elem_part < num_of_all_elements)
1898  {
1899  input.read(reinterpret_cast<char*>(header),
1900  header_size*sizeof(int));
1901  type_of_element = header[0];
1902  n_elem_one_type = header[1];
1903  n_tags = header[2];
1904 
1905  n_elem_part += n_elem_one_type;
1906 
1907  const int n_elem_nodes = nodes_of_gmsh_element[type_of_element-1];
1908  vector<int> data(1+n_tags+n_elem_nodes);
1909  for (int el = 0; el < n_elem_one_type; ++el)
1910  {
1911  input.read(reinterpret_cast<char*>(&data[0]),
1912  data.size()*sizeof(int));
1913  int dd = 0; // index for data array
1914  serial_number = data[dd++];
1915  // physical domain - the most important value (to distinguish
1916  // materials with different properties)
1917  phys_domain = (n_tags > 0) ? data[dd++] : 1;
1918  // elementary domain - to distinguish different geometrical
1919  // domains (typically, it's used rarely)
1920  elem_domain = (n_tags > 1) ? data[dd++] : 0;
1921  // the number of tags is bigger than 2 if there are some
1922  // partitions (domain decompositions)
1923  n_partitions = (n_tags > 2) ? data[dd++] : 0;
1924  // we currently just skip the partitions if they exist, and go
1925  // directly to vertices describing the mesh element
1926  vector<int> vert_indices(n_elem_nodes);
1927  for (int vi = 0; vi < n_elem_nodes; ++vi)
1928  {
1929  map<int, int>::const_iterator it =
1930  vertices_map.find(data[1+n_tags+vi]);
1931  if (it == vertices_map.end())
1932  {
1933  MFEM_ABORT("Gmsh file : vertex index doesn't exist");
1934  }
1935  vert_indices[vi] = it->second;
1936  }
1937 
1938  // non-positive attributes are not allowed in MFEM
1939  if (phys_domain <= 0)
1940  {
1941  MFEM_ABORT("Non-positive element attribute in Gmsh mesh!\n"
1942  "By default Gmsh sets element tags (attributes)"
1943  " to '0' but MFEM requires that they be"
1944  " positive integers.\n"
1945  "Use \"Physical Curve\", \"Physical Surface\","
1946  " or \"Physical Volume\" to set tags/attributes"
1947  " for all curves, surfaces, or volumes in your"
1948  " Gmsh geometry to values which are >= 1.");
1949  }
1950 
1951  // initialize the mesh element
1952  int el_order = 11;
1953  switch (type_of_element)
1954  {
1955  case 1: // 2-node line
1956  case 8: // 3-node line (2nd order)
1957  case 26: // 4-node line (3rd order)
1958  case 27: // 5-node line (4th order)
1959  case 28: // 6-node line (5th order)
1960  case 62: // 7-node line (6th order)
1961  case 63: // 8-node line (7th order)
1962  case 64: // 9-node line (8th order)
1963  case 65: // 10-node line (9th order)
1964  case 66: // 11-node line (10th order)
1965  {
1966  elements_1D.push_back(
1967  new Segment(&vert_indices[0], phys_domain));
1968  if (type_of_element != 1)
1969  {
1970  el_order = n_elem_nodes - 1;
1971  Array<int> * hov = new Array<int>;
1972  hov->Append(&vert_indices[0], n_elem_nodes);
1973  ho_verts_1D.push_back(hov);
1974  ho_el_order_1D.push_back(el_order);
1975  }
1976  break;
1977  }
1978  case 2: el_order--; // 3-node triangle
1979  case 9: el_order--; // 6-node triangle (2nd order)
1980  case 21: el_order--; // 10-node triangle (3rd order)
1981  case 23: el_order--; // 15-node triangle (4th order)
1982  case 25: el_order--; // 21-node triangle (5th order)
1983  case 42: el_order--; // 28-node triangle (6th order)
1984  case 43: el_order--; // 36-node triangle (7th order)
1985  case 44: el_order--; // 45-node triangle (8th order)
1986  case 45: el_order--; // 55-node triangle (9th order)
1987  case 46: el_order--; // 66-node triangle (10th order)
1988  {
1989  elements_2D.push_back(
1990  new Triangle(&vert_indices[0], phys_domain));
1991  if (el_order > 1)
1992  {
1993  Array<int> * hov = new Array<int>;
1994  hov->Append(&vert_indices[0], n_elem_nodes);
1995  ho_verts_2D.push_back(hov);
1996  ho_el_order_2D.push_back(el_order);
1997  }
1998  break;
1999  }
2000  case 3: el_order--; // 4-node quadrangle
2001  case 10: el_order--; // 9-node quadrangle (2nd order)
2002  case 36: el_order--; // 16-node quadrangle (3rd order)
2003  case 37: el_order--; // 25-node quadrangle (4th order)
2004  case 38: el_order--; // 36-node quadrangle (5th order)
2005  case 47: el_order--; // 49-node quadrangle (6th order)
2006  case 48: el_order--; // 64-node quadrangle (7th order)
2007  case 49: el_order--; // 81-node quadrangle (8th order)
2008  case 50: el_order--; // 100-node quadrangle (9th order)
2009  case 51: el_order--; // 121-node quadrangle (10th order)
2010  {
2011  elements_2D.push_back(
2012  new Quadrilateral(&vert_indices[0], phys_domain));
2013  if (el_order > 1)
2014  {
2015  Array<int> * hov = new Array<int>;
2016  hov->Append(&vert_indices[0], n_elem_nodes);
2017  ho_verts_2D.push_back(hov);
2018  ho_el_order_2D.push_back(el_order);
2019  }
2020  break;
2021  }
2022  case 4: el_order--; // 4-node tetrahedron
2023  case 11: el_order--; // 10-node tetrahedron (2nd order)
2024  case 29: el_order--; // 20-node tetrahedron (3rd order)
2025  case 30: el_order--; // 35-node tetrahedron (4th order)
2026  case 31: el_order--; // 56-node tetrahedron (5th order)
2027  case 71: el_order--; // 84-node tetrahedron (6th order)
2028  case 72: el_order--; // 120-node tetrahedron (7th order)
2029  case 73: el_order--; // 165-node tetrahedron (8th order)
2030  case 74: el_order--; // 220-node tetrahedron (9th order)
2031  case 75: el_order--; // 286-node tetrahedron (10th order)
2032  {
2033 #ifdef MFEM_USE_MEMALLOC
2034  elements_3D.push_back(TetMemory.Alloc());
2035  elements_3D.back()->SetVertices(&vert_indices[0]);
2036  elements_3D.back()->SetAttribute(phys_domain);
2037 #else
2038  elements_3D.push_back(
2039  new Tetrahedron(&vert_indices[0], phys_domain));
2040 #endif
2041  if (el_order > 1)
2042  {
2043  Array<int> * hov = new Array<int>;
2044  hov->Append(&vert_indices[0], n_elem_nodes);
2045  ho_verts_3D.push_back(hov);
2046  ho_el_order_3D.push_back(el_order);
2047  }
2048  break;
2049  }
2050  case 5: el_order--; // 8-node hexahedron
2051  case 12: el_order--; // 27-node hexahedron (2nd order)
2052  case 92: el_order--; // 64-node hexahedron (3rd order)
2053  case 93: el_order--; // 125-node hexahedron (4th order)
2054  case 94: el_order--; // 216-node hexahedron (5th order)
2055  case 95: el_order--; // 343-node hexahedron (6th order)
2056  case 96: el_order--; // 512-node hexahedron (7th order)
2057  case 97: el_order--; // 729-node hexahedron (8th order)
2058  case 98: el_order--; // 1000-node hexahedron (9th order)
2059  {
2060  el_order--; // Gmsh does not define an order 10 hex
2061  elements_3D.push_back(
2062  new Hexahedron(&vert_indices[0], phys_domain));
2063  if (el_order > 1)
2064  {
2065  Array<int> * hov = new Array<int>;
2066  hov->Append(&vert_indices[0], n_elem_nodes);
2067  ho_verts_3D.push_back(hov);
2068  ho_el_order_3D.push_back(el_order);
2069  }
2070  break;
2071  }
2072  case 6: el_order--; // 6-node wedge
2073  case 13: el_order--; // 18-node wedge (2nd order)
2074  case 90: el_order--; // 40-node wedge (3rd order)
2075  case 91: el_order--; // 75-node wedge (4th order)
2076  case 106: el_order--; // 126-node wedge (5th order)
2077  case 107: el_order--; // 196-node wedge (6th order)
2078  case 108: el_order--; // 288-node wedge (7th order)
2079  case 109: el_order--; // 405-node wedge (8th order)
2080  case 110: el_order--; // 550-node wedge (9th order)
2081  {
2082  el_order--; // Gmsh does not define an order 10 wedge
2083  elements_3D.push_back(
2084  new Wedge(&vert_indices[0], phys_domain));
2085  if (el_order > 1)
2086  {
2087  Array<int> * hov = new Array<int>;
2088  hov->Append(&vert_indices[0], n_elem_nodes);
2089  ho_verts_3D.push_back(hov);
2090  ho_el_order_3D.push_back(el_order);
2091  }
2092  break;
2093  }
2094  /*
2095  // MFEM does not support pyramids yet
2096  case 7: el_order--; // 5-node pyramid
2097  case 14: el_order--; // 14-node pyramid (2nd order)
2098  case 118: el_order--; // 30-node pyramid (3rd order)
2099  case 119: el_order--; // 55-node pyramid (4th order)
2100  case 120: el_order--; // 91-node pyramid (5th order)
2101  case 121: el_order--; // 140-node pyramid (6th order)
2102  case 122: el_order--; // 204-node pyramid (7th order)
2103  case 123: el_order--; // 285-node pyramid (8th order)
2104  case 124: el_order--; // 385-node pyramid (9th order)
2105  {
2106  el_order--; // Gmsh does not define an order 10 pyr
2107  elements_3D.push_back(
2108  new Pyramid(&vert_indices[0], phys_domain));
2109  if (el_order > 1)
2110  {
2111  Array<int> * hov = new Array<int>;
2112  hov->Append(&vert_indices[0], n_elem_nodes);
2113  ho_verts_3D.push_back(hov);
2114  ho_el_order_3D.push_back(el_order);
2115  }
2116  break;
2117  }
2118  */
2119  case 15: // 1-node point
2120  {
2121  elements_0D.push_back(
2122  new Point(&vert_indices[0], phys_domain));
2123  break;
2124  }
2125  default: // any other element
2126  MFEM_WARNING("Unsupported Gmsh element type.");
2127  break;
2128 
2129  } // switch (type_of_element)
2130  } // el (elements of one type)
2131  } // all elements
2132  } // if binary
2133  else // ASCII
2134  {
2135  for (int el = 0; el < num_of_all_elements; ++el)
2136  {
2137  input >> serial_number >> type_of_element >> n_tags;
2138  vector<int> data(n_tags);
2139  for (int i = 0; i < n_tags; ++i) { input >> data[i]; }
2140  // physical domain - the most important value (to distinguish
2141  // materials with different properties)
2142  phys_domain = (n_tags > 0) ? data[0] : 1;
2143  // elementary domain - to distinguish different geometrical
2144  // domains (typically, it's used rarely)
2145  elem_domain = (n_tags > 1) ? data[1] : 0;
2146  // the number of tags is bigger than 2 if there are some
2147  // partitions (domain decompositions)
2148  n_partitions = (n_tags > 2) ? data[2] : 0;
2149  // we currently just skip the partitions if they exist, and go
2150  // directly to vertices describing the mesh element
2151  const int n_elem_nodes = nodes_of_gmsh_element[type_of_element-1];
2152  vector<int> vert_indices(n_elem_nodes);
2153  int index;
2154  for (int vi = 0; vi < n_elem_nodes; ++vi)
2155  {
2156  input >> index;
2157  map<int, int>::const_iterator it = vertices_map.find(index);
2158  if (it == vertices_map.end())
2159  {
2160  MFEM_ABORT("Gmsh file : vertex index doesn't exist");
2161  }
2162  vert_indices[vi] = it->second;
2163  }
2164 
2165  // non-positive attributes are not allowed in MFEM
2166  if (phys_domain <= 0)
2167  {
2168  MFEM_ABORT("Non-positive element attribute in Gmsh mesh!\n"
2169  "By default Gmsh sets element tags (attributes)"
2170  " to '0' but MFEM requires that they be"
2171  " positive integers.\n"
2172  "Use \"Physical Curve\", \"Physical Surface\","
2173  " or \"Physical Volume\" to set tags/attributes"
2174  " for all curves, surfaces, or volumes in your"
2175  " Gmsh geometry to values which are >= 1.");
2176  }
2177 
2178  // initialize the mesh element
2179  int el_order = 11;
2180  switch (type_of_element)
2181  {
2182  case 1: // 2-node line
2183  case 8: // 3-node line (2nd order)
2184  case 26: // 4-node line (3rd order)
2185  case 27: // 5-node line (4th order)
2186  case 28: // 6-node line (5th order)
2187  case 62: // 7-node line (6th order)
2188  case 63: // 8-node line (7th order)
2189  case 64: // 9-node line (8th order)
2190  case 65: // 10-node line (9th order)
2191  case 66: // 11-node line (10th order)
2192  {
2193  elements_1D.push_back(
2194  new Segment(&vert_indices[0], phys_domain));
2195  if (type_of_element != 1)
2196  {
2197  Array<int> * hov = new Array<int>;
2198  hov->Append(&vert_indices[0], n_elem_nodes);
2199  ho_verts_1D.push_back(hov);
2200  el_order = n_elem_nodes - 1;
2201  ho_el_order_1D.push_back(el_order);
2202  }
2203  break;
2204  }
2205  case 2: el_order--; // 3-node triangle
2206  case 9: el_order--; // 6-node triangle (2nd order)
2207  case 21: el_order--; // 10-node triangle (3rd order)
2208  case 23: el_order--; // 15-node triangle (4th order)
2209  case 25: el_order--; // 21-node triangle (5th order)
2210  case 42: el_order--; // 28-node triangle (6th order)
2211  case 43: el_order--; // 36-node triangle (7th order)
2212  case 44: el_order--; // 45-node triangle (8th order)
2213  case 45: el_order--; // 55-node triangle (9th order)
2214  case 46: el_order--; // 66-node triangle (10th order)
2215  {
2216  elements_2D.push_back(
2217  new Triangle(&vert_indices[0], phys_domain));
2218  if (el_order > 1)
2219  {
2220  Array<int> * hov = new Array<int>;
2221  hov->Append(&vert_indices[0], n_elem_nodes);
2222  ho_verts_2D.push_back(hov);
2223  ho_el_order_2D.push_back(el_order);
2224  }
2225  break;
2226  }
2227  case 3: el_order--; // 4-node quadrangle
2228  case 10: el_order--; // 9-node quadrangle (2nd order)
2229  case 36: el_order--; // 16-node quadrangle (3rd order)
2230  case 37: el_order--; // 25-node quadrangle (4th order)
2231  case 38: el_order--; // 36-node quadrangle (5th order)
2232  case 47: el_order--; // 49-node quadrangle (6th order)
2233  case 48: el_order--; // 64-node quadrangle (7th order)
2234  case 49: el_order--; // 81-node quadrangle (8th order)
2235  case 50: el_order--; // 100-node quadrangle (9th order)
2236  case 51: el_order--; // 121-node quadrangle (10th order)
2237  {
2238  elements_2D.push_back(
2239  new Quadrilateral(&vert_indices[0], phys_domain));
2240  if (el_order > 1)
2241  {
2242  Array<int> * hov = new Array<int>;
2243  hov->Append(&vert_indices[0], n_elem_nodes);
2244  ho_verts_2D.push_back(hov);
2245  ho_el_order_2D.push_back(el_order);
2246  }
2247  break;
2248  }
2249  case 4: el_order--; // 4-node tetrahedron
2250  case 11: el_order--; // 10-node tetrahedron (2nd order)
2251  case 29: el_order--; // 20-node tetrahedron (3rd order)
2252  case 30: el_order--; // 35-node tetrahedron (4th order)
2253  case 31: el_order--; // 56-node tetrahedron (5th order)
2254  case 71: el_order--; // 84-node tetrahedron (6th order)
2255  case 72: el_order--; // 120-node tetrahedron (7th order)
2256  case 73: el_order--; // 165-node tetrahedron (8th order)
2257  case 74: el_order--; // 220-node tetrahedron (9th order)
2258  case 75: el_order--; // 286-node tetrahedron (10th order)
2259  {
2260 #ifdef MFEM_USE_MEMALLOC
2261  elements_3D.push_back(TetMemory.Alloc());
2262  elements_3D.back()->SetVertices(&vert_indices[0]);
2263  elements_3D.back()->SetAttribute(phys_domain);
2264 #else
2265  elements_3D.push_back(
2266  new Tetrahedron(&vert_indices[0], phys_domain));
2267 #endif
2268  if (el_order > 1)
2269  {
2270  Array<int> * hov = new Array<int>;
2271  hov->Append(&vert_indices[0], n_elem_nodes);
2272  ho_verts_3D.push_back(hov);
2273  ho_el_order_3D.push_back(el_order);
2274  }
2275  break;
2276  }
2277  case 5: el_order--; // 8-node hexahedron
2278  case 12: el_order--; // 27-node hexahedron (2nd order)
2279  case 92: el_order--; // 64-node hexahedron (3rd order)
2280  case 93: el_order--; // 125-node hexahedron (4th order)
2281  case 94: el_order--; // 216-node hexahedron (5th order)
2282  case 95: el_order--; // 343-node hexahedron (6th order)
2283  case 96: el_order--; // 512-node hexahedron (7th order)
2284  case 97: el_order--; // 729-node hexahedron (8th order)
2285  case 98: el_order--; // 1000-node hexahedron (9th order)
2286  {
2287  el_order--;
2288  elements_3D.push_back(
2289  new Hexahedron(&vert_indices[0], phys_domain));
2290  if (el_order > 1)
2291  {
2292  Array<int> * hov = new Array<int>;
2293  hov->Append(&vert_indices[0], n_elem_nodes);
2294  ho_verts_3D.push_back(hov);
2295  ho_el_order_3D.push_back(el_order);
2296  }
2297  break;
2298  }
2299  case 6: el_order--; // 6-node wedge
2300  case 13: el_order--; // 18-node wedge (2nd order)
2301  case 90: el_order--; // 40-node wedge (3rd order)
2302  case 91: el_order--; // 75-node wedge (4th order)
2303  case 106: el_order--; // 126-node wedge (5th order)
2304  case 107: el_order--; // 196-node wedge (6th order)
2305  case 108: el_order--; // 288-node wedge (7th order)
2306  case 109: el_order--; // 405-node wedge (8th order)
2307  case 110: el_order--; // 550-node wedge (9th order)
2308  {
2309  el_order--;
2310  elements_3D.push_back(
2311  new Wedge(&vert_indices[0], phys_domain));
2312  if (el_order > 1)
2313  {
2314  Array<int> * hov = new Array<int>;
2315  hov->Append(&vert_indices[0], n_elem_nodes);
2316  ho_verts_3D.push_back(hov);
2317  ho_el_order_3D.push_back(el_order);
2318  }
2319  break;
2320  }
2321  /*
2322  // MFEM does not support pyramids yet
2323  case 7: el_order--; // 5-node pyramid
2324  case 14: el_order--; // 14-node pyramid (2nd order)
2325  case 118: el_order--; // 30-node pyramid (3rd order)
2326  case 119: el_order--; // 55-node pyramid (4th order)
2327  case 120: el_order--; // 91-node pyramid (5th order)
2328  case 121: el_order--; // 140-node pyramid (6th order)
2329  case 122: el_order--; // 204-node pyramid (7th order)
2330  case 123: el_order--; // 285-node pyramid (8th order)
2331  case 124: el_order--; // 385-node pyramid (9th order)
2332  {
2333  el_order--;
2334  elements_3D.push_back(
2335  new Pyramid(&vert_indices[0], phys_domain));
2336  if (el_order > 1)
2337  {
2338  Array<int> * hov = new Array<int>;
2339  hov->Append(&vert_indices[0], n_elem_nodes);
2340  ho_verts_3D.push_back(hov);
2341  ho_el_order_3D.push_back(el_order);
2342  }
2343  break;
2344  }
2345  */
2346  case 15: // 1-node point
2347  {
2348  elements_0D.push_back(
2349  new Point(&vert_indices[0], phys_domain));
2350  break;
2351  }
2352  default: // any other element
2353  MFEM_WARNING("Unsupported Gmsh element type.");
2354  break;
2355 
2356  } // switch (type_of_element)
2357  } // el (all elements)
2358  } // if ASCII
2359 
2360  if (!elements_3D.empty())
2361  {
2362  Dim = 3;
2363  NumOfElements = elements_3D.size();
2364  elements.SetSize(NumOfElements);
2365  for (int el = 0; el < NumOfElements; ++el)
2366  {
2367  elements[el] = elements_3D[el];
2368  }
2369  NumOfBdrElements = elements_2D.size();
2370  boundary.SetSize(NumOfBdrElements);
2371  for (int el = 0; el < NumOfBdrElements; ++el)
2372  {
2373  boundary[el] = elements_2D[el];
2374  }
2375  for (size_t el = 0; el < ho_el_order_3D.size(); el++)
2376  {
2377  mesh_order = max(mesh_order, ho_el_order_3D[el]);
2378  }
2379  // discard other elements
2380  for (size_t el = 0; el < elements_1D.size(); ++el)
2381  {
2382  delete elements_1D[el];
2383  }
2384  for (size_t el = 0; el < elements_0D.size(); ++el)
2385  {
2386  delete elements_0D[el];
2387  }
2388  }
2389  else if (!elements_2D.empty())
2390  {
2391  Dim = 2;
2392  NumOfElements = elements_2D.size();
2393  elements.SetSize(NumOfElements);
2394  for (int el = 0; el < NumOfElements; ++el)
2395  {
2396  elements[el] = elements_2D[el];
2397  }
2398  NumOfBdrElements = elements_1D.size();
2399  boundary.SetSize(NumOfBdrElements);
2400  for (int el = 0; el < NumOfBdrElements; ++el)
2401  {
2402  boundary[el] = elements_1D[el];
2403  }
2404  for (size_t el = 0; el < ho_el_order_2D.size(); el++)
2405  {
2406  mesh_order = max(mesh_order, ho_el_order_2D[el]);
2407  }
2408  // discard other elements
2409  for (size_t el = 0; el < elements_0D.size(); ++el)
2410  {
2411  delete elements_0D[el];
2412  }
2413  }
2414  else if (!elements_1D.empty())
2415  {
2416  Dim = 1;
2417  NumOfElements = elements_1D.size();
2418  elements.SetSize(NumOfElements);
2419  for (int el = 0; el < NumOfElements; ++el)
2420  {
2421  elements[el] = elements_1D[el];
2422  }
2423  NumOfBdrElements = elements_0D.size();
2424  boundary.SetSize(NumOfBdrElements);
2425  for (int el = 0; el < NumOfBdrElements; ++el)
2426  {
2427  boundary[el] = elements_0D[el];
2428  }
2429  for (size_t el = 0; el < ho_el_order_1D.size(); el++)
2430  {
2431  mesh_order = max(mesh_order, ho_el_order_1D[el]);
2432  }
2433  }
2434  else
2435  {
2436  MFEM_ABORT("Gmsh file : no elements found");
2437  return;
2438  }
2439 
2440  if (mesh_order > 1)
2441  {
2442  curved = 1;
2443  read_gf = 0;
2444 
2445  // initialize mesh_geoms so we can create Nodes FE space below
2446  this->SetMeshGen();
2447 
2448  // Construct GridFunction for uniformly spaced high order coords
2450  FiniteElementSpace* nfes;
2451  nfec = new L2_FECollection(mesh_order, Dim,
2452  BasisType::ClosedUniform);
2453  nfes = new FiniteElementSpace(this, nfec, spaceDim,
2454  Ordering::byVDIM);
2455  Nodes_gf.SetSpace(nfes);
2456  Nodes_gf.MakeOwner(nfec);
2457 
2458  int o = 0;
2459  int el_order = 1;
2460  for (int el = 0; el < NumOfElements; el++)
2461  {
2462  const int * vm = NULL;
2463  Array<int> * ho_verts = NULL;
2464  switch (GetElementType(el))
2465  {
2466  case Element::SEGMENT:
2467  ho_verts = ho_verts_1D[el];
2468  el_order = ho_el_order_1D[el];
2469  if (!ho_lin[el_order])
2470  {
2471  ho_lin[el_order] = new int[ho_verts->Size()];
2472  GmshHOSegmentMapping(el_order, ho_lin[el_order]);
2473  }
2474  vm = ho_lin[el_order];
2475  break;
2476  case Element::TRIANGLE:
2477  ho_verts = ho_verts_2D[el];
2478  el_order = ho_el_order_2D[el];
2479  if (!ho_tri[el_order])
2480  {
2481  ho_tri[el_order] = new int[ho_verts->Size()];
2482  GmshHOTriangleMapping(el_order, ho_tri[el_order]);
2483  }
2484  vm = ho_tri[el_order];
2485  break;
2486  case Element::QUADRILATERAL:
2487  ho_verts = ho_verts_2D[el];
2488  el_order = ho_el_order_2D[el];
2489  if (!ho_sqr[el_order])
2490  {
2491  ho_sqr[el_order] = new int[ho_verts->Size()];
2492  GmshHOQuadrilateralMapping(el_order, ho_sqr[el_order]);
2493  }
2494  vm = ho_sqr[el_order];
2495  break;
2496  case Element::TETRAHEDRON:
2497  ho_verts = ho_verts_3D[el];
2498  el_order = ho_el_order_3D[el];
2499  if (!ho_tet[el_order])
2500  {
2501  ho_tet[el_order] = new int[ho_verts->Size()];
2502  GmshHOTetrahedronMapping(el_order, ho_tet[el_order]);
2503  }
2504  vm = ho_tet[el_order];
2505  break;
2506  case Element::HEXAHEDRON:
2507  ho_verts = ho_verts_3D[el];
2508  el_order = ho_el_order_3D[el];
2509  if (!ho_hex[el_order])
2510  {
2511  ho_hex[el_order] = new int[ho_verts->Size()];
2512  GmshHOHexahedronMapping(el_order, ho_hex[el_order]);
2513  }
2514  vm = ho_hex[el_order];
2515  break;
2516  case Element::WEDGE:
2517  ho_verts = ho_verts_3D[el];
2518  el_order = ho_el_order_3D[el];
2519  if (!ho_wdg[el_order])
2520  {
2521  ho_wdg[el_order] = new int[ho_verts->Size()];
2522  GmshHOWedgeMapping(el_order, ho_wdg[el_order]);
2523  }
2524  vm = ho_wdg[el_order];
2525  break;
2526  // case Element::PYRAMID:
2527  // ho_verts = ho_verts_3D[el];
2528  // el_order = ho_el_order_3D[el];
2529  // if (ho_pyr[el_order])
2530  // {
2531  // ho_pyr[el_order] = new int[ho_verts->Size()];
2532  // GmshHOPyramidMapping(el_order, ho_pyr[el_order]);
2533  // }
2534  // vm = ho_pyr[el_order];
2535  // break;
2536  default: // Any other element type
2537  MFEM_WARNING("Unsupported Gmsh element type.");
2538  break;
2539  }
2540  int nv = (ho_verts) ? ho_verts->Size() : 0;
2541 
2542  for (int v = 0; v<nv; v++)
2543  {
2544  double * c = GetVertex((*ho_verts)[vm[v]]);
2545  for (int d=0; d<spaceDim; d++)
2546  {
2547  Nodes_gf(spaceDim * (o + v) + d) = c[d];
2548  }
2549  }
2550  o += nv;
2551  }
2552  }
2553 
2554  // Delete any high order element to vertex connectivity
2555  for (size_t el=0; el<ho_verts_1D.size(); el++)
2556  {
2557  delete ho_verts_1D[el];
2558  }
2559  for (size_t el=0; el<ho_verts_2D.size(); el++)
2560  {
2561  delete ho_verts_2D[el];
2562  }
2563  for (size_t el=0; el<ho_verts_3D.size(); el++)
2564  {
2565  delete ho_verts_3D[el];
2566  }
2567 
2568  // Delete dynamically allocated high vertex order mappings
2569  for (int ord=4; ord<ho_lin.Size(); ord++)
2570  {
2571  if (ho_lin[ord] != NULL) { delete [] ho_lin[ord]; }
2572  }
2573  for (int ord=4; ord<ho_tri.Size(); ord++)
2574  {
2575  if (ho_tri[ord] != NULL) { delete [] ho_tri[ord]; }
2576  }
2577  for (int ord=4; ord<ho_sqr.Size(); ord++)
2578  {
2579  if (ho_sqr[ord] != NULL) { delete [] ho_sqr[ord]; }
2580  }
2581  for (int ord=4; ord<ho_tet.Size(); ord++)
2582  {
2583  if (ho_tet[ord] != NULL) { delete [] ho_tet[ord]; }
2584  }
2585  for (int ord=4; ord<ho_hex.Size(); ord++)
2586  {
2587  if (ho_hex[ord] != NULL) { delete [] ho_hex[ord]; }
2588  }
2589  for (int ord=4; ord<ho_wdg.Size(); ord++)
2590  {
2591  if (ho_wdg[ord] != NULL) { delete [] ho_wdg[ord]; }
2592  }
2593  for (int ord=4; ord<ho_pyr.Size(); ord++)
2594  {
2595  if (ho_pyr[ord] != NULL) { delete [] ho_pyr[ord]; }
2596  }
2597 
2598  MFEM_CONTRACT_VAR(n_partitions);
2599  MFEM_CONTRACT_VAR(elem_domain);
2600 
2601  } // section '$Elements'
2602  else if (buff == "$Periodic") // Reading master/slave node pairs
2603  {
2604  curved = 1;
2605  read_gf = 0;
2606  periodic = true;
2607 
2608  Array<int> v2v(NumOfVertices);
2609  for (int i = 0; i < v2v.Size(); i++)
2610  {
2611  v2v[i] = i;
2612  }
2613  int num_per_ent;
2614  int num_nodes;
2615  int slave, master;
2616  input >> num_per_ent;
2617  getline(input, buff); // Read end-of-line
2618  for (int i = 0; i < num_per_ent; i++)
2619  {
2620  getline(input, buff); // Read and ignore entity dimension and tags
2621  getline(input, buff); // If affine mapping exist, read and ignore
2622  if (!strncmp(buff.c_str(), "Affine", 6))
2623  {
2624  input >> num_nodes;
2625  }
2626  else
2627  {
2628  num_nodes = atoi(buff.c_str());
2629  }
2630  for (int j=0; j<num_nodes; j++)
2631  {
2632  input >> slave >> master;
2633  v2v[slave - 1] = master - 1;
2634  }
2635  getline(input, buff); // Read end-of-line
2636  }
2637 
2638  // Follow existing long chains of slave->master in v2v array.
2639  // Upon completion of this loop, each v2v[slave] will point to a true
2640  // master vertex. This algorithm is useful for periodicity defined in
2641  // multiple directions.
2642  for (int slave = 0; slave < v2v.Size(); slave++)
2643  {
2644  int master = v2v[slave];
2645  if (master != slave)
2646  {
2647  // This loop will end if it finds a circular dependency.
2648  while (v2v[master] != master && master != slave)
2649  {
2650  master = v2v[master];
2651  }
2652  if (master == slave)
2653  {
2654  // if master and slave are the same vertex, circular dependency
2655  // exists. We need to fix the problem, we choose slave.
2656  v2v[slave] = slave;
2657  }
2658  else
2659  {
2660  // the long chain has ended on the true master vertex.
2661  v2v[slave] = master;
2662  }
2663  }
2664  }
2665 
2666  // Convert nodes to discontinuous GridFunction (if they aren't already)
2667  if (mesh_order == 1)
2668  {
2669  this->SetMeshGen();
2670  this->SetCurvature(1, true, spaceDim, Ordering::byVDIM);
2671  }
2672 
2673  // Replace "slave" vertex indices in the element connectivity
2674  // with their corresponding "master" vertex indices.
2675  for (int i = 0; i < this->GetNE(); i++)
2676  {
2677  Element *el = this->GetElement(i);
2678  int *v = el->GetVertices();
2679  int nv = el->GetNVertices();
2680  for (int j = 0; j < nv; j++)
2681  {
2682  v[j] = v2v[v[j]];
2683  }
2684  }
2685  // Replace "slave" vertex indices in the boundary element connectivity
2686  // with their corresponding "master" vertex indices.
2687  for (int i = 0; i < this->GetNBE(); i++)
2688  {
2689  Element *el = this->GetBdrElement(i);
2690  int *v = el->GetVertices();
2691  int nv = el->GetNVertices();
2692  for (int j = 0; j < nv; j++)
2693  {
2694  v[j] = v2v[v[j]];
2695  }
2696  }
2697  }
2698  } // we reach the end of the file
2699 
2700  this->RemoveUnusedVertices();
2701  if (periodic)
2702  {
2703  this->RemoveInternalBoundaries();
2704  }
2705  this->FinalizeTopology();
2706 
2707  // If a high order coordinate field was created project it onto the mesh
2708  if (mesh_order > 1)
2709  {
2710  SetCurvature(mesh_order, periodic, spaceDim, Ordering::byVDIM);
2711 
2712  VectorGridFunctionCoefficient NodesCoef(&Nodes_gf);
2713  Nodes->ProjectCoefficient(NodesCoef);
2714  }
2715 }
2716 
2717 
2718 #ifdef MFEM_USE_NETCDF
2719 void Mesh::ReadCubit(const char *filename, int &curved, int &read_gf)
2720 {
2721  read_gf = 0;
2722 
2723  // curved set to zero will change if mesh is indeed curved
2724  curved = 0;
2725 
2726  const int sideMapTri3[3][2] =
2727  {
2728  {1,2},
2729  {2,3},
2730  {3,1},
2731  };
2732 
2733  const int sideMapQuad4[4][2] =
2734  {
2735  {1,2},
2736  {2,3},
2737  {3,4},
2738  {4,1},
2739  };
2740 
2741  const int sideMapTri6[3][3] =
2742  {
2743  {1,2,4},
2744  {2,3,5},
2745  {3,1,6},
2746  };
2747 
2748  const int sideMapQuad9[4][3] =
2749  {
2750  {1,2,5},
2751  {2,3,6},
2752  {3,4,7},
2753  {4,1,8},
2754  };
2755 
2756  const int sideMapTet4[4][3] =
2757  {
2758  {1,2,4},
2759  {2,3,4},
2760  {1,4,3},
2761  {1,3,2}
2762  };
2763 
2764  const int sideMapTet10[4][6] =
2765  {
2766  {1,2,4,5,9,8},
2767  {2,3,4,6,10,9},
2768  {1,4,3,8,10,7},
2769  {1,3,2,7,6,5}
2770  };
2771 
2772  const int sideMapHex8[6][4] =
2773  {
2774  {1,2,6,5},
2775  {2,3,7,6},
2776  {4,3,7,8},
2777  {1,4,8,5},
2778  {1,4,3,2},
2779  {5,8,7,6}
2780  };
2781 
2782  const int sideMapHex27[6][9] =
2783  {
2784  {1,2,6,5,9,14,17,13,26},
2785  {2,3,7,6,10,15,18,14,25},
2786  {4,3,7,8,11,15,19,16,27},
2787  {1,4,8,5,12,16,20,13,24},
2788  {1,4,3,2,12,11,10,9,22},
2789  {5,8,7,6,20,19,18,17,23}
2790  };
2791 
2792 
2793  // 1,2,3,4,5,6,7,8,9,10
2794  const int mfemToGenesisTet10[10] = {1,2,3,4,5,7,8,6,9,10};
2795 
2796  // 1,2,3,4,5,6,7,8,9,10,11,
2797  const int mfemToGenesisHex27[27] = {1,2,3,4,5,6,7,8,9,10,11,
2798  // 12,13,14,15,16,17,18,19
2799  12,17,18,19,20,13,14,15,
2800  // 20,21,22,23,24,25,26,27
2801  16,22,26,25,27,24,23,21
2802  };
2803 
2804  const int mfemToGenesisTri6[6] = {1,2,3,4,5,6};
2805  const int mfemToGenesisQuad9[9] = {1,2,3,4,5,6,7,8,9};
2806 
2807 
2808  // error handling.
2809  int retval;
2810 
2811  // dummy string
2812  char str_dummy[256];
2813 
2814  char temp_str[256];
2815  int temp_id;
2816 
2817  // open the file.
2818  int ncid;
2819  if ((retval = nc_open(filename, NC_NOWRITE, &ncid)))
2820  {
2821  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
2822  }
2823 
2824  // read important dimensions
2825 
2826  int id;
2827  size_t num_dim=0, num_nodes=0, num_elem=0, num_el_blk=0, num_side_sets=0;
2828 
2829  if ((retval = nc_inq_dimid(ncid, "num_dim", &id)) ||
2830  (retval = nc_inq_dim(ncid, id, str_dummy, &num_dim)) ||
2831 
2832  (retval = nc_inq_dimid(ncid, "num_nodes", &id)) ||
2833  (retval = nc_inq_dim(ncid, id, str_dummy, &num_nodes)) ||
2834 
2835  (retval = nc_inq_dimid(ncid, "num_elem", &id)) ||
2836  (retval = nc_inq_dim(ncid, id, str_dummy, &num_elem)) ||
2837 
2838  (retval = nc_inq_dimid(ncid, "num_el_blk", &id)) ||
2839  (retval = nc_inq_dim(ncid, id, str_dummy, &num_el_blk)))
2840  {
2841  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
2842  }
2843  if ((retval = nc_inq_dimid(ncid, "num_side_sets", &id)) ||
2844  (retval = nc_inq_dim(ncid, id, str_dummy, &num_side_sets)))
2845  {
2846  num_side_sets = 0;
2847  }
2848 
2849  Dim = num_dim;
2850 
2851  // create arrays for element blocks
2852  size_t *num_el_in_blk = new size_t[num_el_blk];
2853  size_t num_node_per_el;
2854 
2855  int previous_num_node_per_el = 0;
2856  for (int i = 0; i < (int) num_el_blk; i++)
2857  {
2858  sprintf(temp_str, "num_el_in_blk%d", i+1);
2859  if ((retval = nc_inq_dimid(ncid, temp_str, &temp_id)) ||
2860  (retval = nc_inq_dim(ncid, temp_id, str_dummy, &num_el_in_blk[i])))
2861  {
2862  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
2863  }
2864 
2865  sprintf(temp_str, "num_nod_per_el%d", i+1);
2866  if ((retval = nc_inq_dimid(ncid, temp_str, &temp_id)) ||
2867  (retval = nc_inq_dim(ncid, temp_id, str_dummy, &num_node_per_el)))
2868  {
2869  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
2870  }
2871 
2872  // check for different element types in each block
2873  // which is not currently supported
2874  if (i != 0)
2875  {
2876  if ((int) num_node_per_el != previous_num_node_per_el)
2877  {
2878  MFEM_ABORT("Element blocks of different element types not supported");
2879  }
2880  }
2881  previous_num_node_per_el = num_node_per_el;
2882  }
2883 
2884  // Determine CUBIT element and face type
2885  enum CubitElementType
2886  {
2887  ELEMENT_TRI3,
2888  ELEMENT_TRI6,
2889  ELEMENT_QUAD4,
2890  ELEMENT_QUAD9,
2891  ELEMENT_TET4,
2892  ELEMENT_TET10,
2893  ELEMENT_HEX8,
2894  ELEMENT_HEX27
2895  };
2896 
2897  enum CubitFaceType
2898  {
2899  FACE_EDGE2,
2900  FACE_EDGE3,
2901  FACE_TRI3,
2902  FACE_TRI6,
2903  FACE_QUAD4,
2904  FACE_QUAD9
2905  };
2906 
2907  CubitElementType cubit_element_type = ELEMENT_TRI3; // suppress a warning
2908  CubitFaceType cubit_face_type = FACE_EDGE2; // suppress a warning
2909  int num_element_linear_nodes = 0; // initialize to suppress a warning
2910 
2911  if (num_dim == 2)
2912  {
2913  switch (num_node_per_el)
2914  {
2915  case (3) :
2916  {
2917  cubit_element_type = ELEMENT_TRI3;
2918  cubit_face_type = FACE_EDGE2;
2919  num_element_linear_nodes = 3;
2920  break;
2921  }
2922  case (6) :
2923  {
2924  cubit_element_type = ELEMENT_TRI6;
2925  cubit_face_type = FACE_EDGE3;
2926  num_element_linear_nodes = 3;
2927  break;
2928  }
2929  case (4) :
2930  {
2931  cubit_element_type = ELEMENT_QUAD4;
2932  cubit_face_type = FACE_EDGE2;
2933  num_element_linear_nodes = 4;
2934  break;
2935  }
2936  case (9) :
2937  {
2938  cubit_element_type = ELEMENT_QUAD9;
2939  cubit_face_type = FACE_EDGE3;
2940  num_element_linear_nodes = 4;
2941  break;
2942  }
2943  default :
2944  {
2945  MFEM_ABORT("Don't know what to do with a " << num_node_per_el <<
2946  " node 2D element\n");
2947  }
2948  }
2949  }
2950  else if (num_dim == 3)
2951  {
2952  switch (num_node_per_el)
2953  {
2954  case (4) :
2955  {
2956  cubit_element_type = ELEMENT_TET4;
2957  cubit_face_type = FACE_TRI3;
2958  num_element_linear_nodes = 4;
2959  break;
2960  }
2961  case (10) :
2962  {
2963  cubit_element_type = ELEMENT_TET10;
2964  cubit_face_type = FACE_TRI6;
2965  num_element_linear_nodes = 4;
2966  break;
2967  }
2968  case (8) :
2969  {
2970  cubit_element_type = ELEMENT_HEX8;
2971  cubit_face_type = FACE_QUAD4;
2972  num_element_linear_nodes = 8;
2973  break;
2974  }
2975  case (27) :
2976  {
2977  cubit_element_type = ELEMENT_HEX27;
2978  cubit_face_type = FACE_QUAD9;
2979  num_element_linear_nodes = 8;
2980  break;
2981  }
2982  default :
2983  {
2984  MFEM_ABORT("Don't know what to do with a " << num_node_per_el <<
2985  " node 3D element\n");
2986  }
2987  }
2988  }
2989  else
2990  {
2991  MFEM_ABORT("Invalid dimension: num_dim = " << num_dim);
2992  }
2993 
2994  // Determine order of elements
2995  int order = 0;
2996  if (cubit_element_type == ELEMENT_TRI3 || cubit_element_type == ELEMENT_QUAD4 ||
2997  cubit_element_type == ELEMENT_TET4 || cubit_element_type == ELEMENT_HEX8)
2998  {
2999  order = 1;
3000  }
3001  else if (cubit_element_type == ELEMENT_TRI6 ||
3002  cubit_element_type == ELEMENT_QUAD9 ||
3003  cubit_element_type == ELEMENT_TET10 || cubit_element_type == ELEMENT_HEX27)
3004  {
3005  order = 2;
3006  }
3007 
3008  // create array for number of sides in side sets
3009  size_t *num_side_in_ss = new size_t[num_side_sets];
3010  for (int i = 0; i < (int) num_side_sets; i++)
3011  {
3012  sprintf(temp_str, "num_side_ss%d", i+1);
3013  if ((retval = nc_inq_dimid(ncid, temp_str, &temp_id)) ||
3014  (retval = nc_inq_dim(ncid, temp_id, str_dummy, &num_side_in_ss[i])))
3015  {
3016  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
3017  }
3018  }
3019 
3020  // read the coordinates
3021  double *coordx = new double[num_nodes];
3022  double *coordy = new double[num_nodes];
3023  double *coordz = new double[num_nodes];
3024 
3025  if ((retval = nc_inq_varid(ncid, "coordx", &id)) ||
3026  (retval = nc_get_var_double(ncid, id, coordx)) ||
3027  (retval = nc_inq_varid(ncid, "coordy", &id)) ||
3028  (retval = nc_get_var_double(ncid, id, coordy)))
3029  {
3030  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
3031  }
3032 
3033  if (num_dim == 3)
3034  {
3035  if ((retval = nc_inq_varid(ncid, "coordz", &id)) ||
3036  (retval = nc_get_var_double(ncid, id, coordz)))
3037  {
3038  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
3039  }
3040  }
3041 
3042  // read the element blocks
3043  int **elem_blk = new int*[num_el_blk];
3044  for (int i = 0; i < (int) num_el_blk; i++)
3045  {
3046  elem_blk[i] = new int[num_el_in_blk[i] * num_node_per_el];
3047  sprintf(temp_str, "connect%d", i+1);
3048  if ((retval = nc_inq_varid(ncid, temp_str, &temp_id)) ||
3049  (retval = nc_get_var_int(ncid, temp_id, elem_blk[i])))
3050  {
3051  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
3052  }
3053  }
3054  int *ebprop = new int[num_el_blk];
3055  if ((retval = nc_inq_varid(ncid, "eb_prop1", &id)) ||
3056  (retval = nc_get_var_int(ncid, id, ebprop)))
3057  {
3058  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
3059  }
3060 
3061  // read the side sets, a side is is given by (element, face) pairs
3062 
3063  int **elem_ss = new int*[num_side_sets];
3064  int **side_ss = new int*[num_side_sets];
3065 
3066  for (int i = 0; i < (int) num_side_sets; i++)
3067  {
3068  elem_ss[i] = new int[num_side_in_ss[i]];
3069  side_ss[i] = new int[num_side_in_ss[i]];
3070 
3071  sprintf(temp_str, "elem_ss%d", i+1);
3072  if ((retval = nc_inq_varid(ncid, temp_str, &temp_id)) ||
3073  (retval = nc_get_var_int(ncid, temp_id, elem_ss[i])))
3074  {
3075  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
3076  }
3077 
3078  sprintf(temp_str,"side_ss%d",i+1);
3079  if ((retval = nc_inq_varid(ncid, temp_str, &temp_id)) ||
3080  (retval = nc_get_var_int(ncid, temp_id, side_ss[i])))
3081  {
3082  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
3083  }
3084  }
3085 
3086  int *ssprop = new int[num_side_sets];
3087  if ((num_side_sets > 0) &&
3088  ((retval = nc_inq_varid(ncid, "ss_prop1", &id)) ||
3089  (retval = nc_get_var_int(ncid, id, ssprop))))
3090  {
3091  MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
3092  }
3093 
3094  // convert (elem,side) pairs to 2D elements
3095 
3096 
3097  int num_face_nodes = 0;
3098  int num_face_linear_nodes = 0;
3099 
3100  switch (cubit_face_type)
3101  {
3102  case (FACE_EDGE2):
3103  {
3104  num_face_nodes = 2;
3105  num_face_linear_nodes = 2;
3106  break;
3107  }
3108  case (FACE_EDGE3):
3109  {
3110  num_face_nodes = 3;
3111  num_face_linear_nodes = 2;
3112  break;
3113  }
3114  case (FACE_TRI3):
3115  {
3116  num_face_nodes = 3;
3117  num_face_linear_nodes = 3;
3118  break;
3119  }
3120  case (FACE_TRI6):
3121  {
3122  num_face_nodes = 6;
3123  num_face_linear_nodes = 3;
3124  break;
3125  }
3126  case (FACE_QUAD4):
3127  {
3128  num_face_nodes = 4;
3129  num_face_linear_nodes = 4;
3130  break;
3131  }
3132  case (FACE_QUAD9):
3133  {
3134  num_face_nodes = 9;
3135  num_face_linear_nodes = 4;
3136  break;
3137  }
3138  }
3139 
3140  // given a global element number, determine the element block and local
3141  // element number
3142  int *start_of_block = new int[num_el_blk+1];
3143  start_of_block[0] = 0;
3144  for (int i = 1; i < (int) num_el_blk+1; i++)
3145  {
3146  start_of_block[i] = start_of_block[i-1] + num_el_in_blk[i-1];
3147  }
3148 
3149  int **ss_node_id = new int*[num_side_sets];
3150 
3151  for (int i = 0; i < (int) num_side_sets; i++)
3152  {
3153  ss_node_id[i] = new int[num_side_in_ss[i]*num_face_nodes];
3154  for (int j = 0; j < (int) num_side_in_ss[i]; j++)
3155  {
3156  int glob_ind = elem_ss[i][j]-1;
3157  int iblk = 0;
3158  int loc_ind;
3159  while (iblk < (int) num_el_blk && glob_ind >= start_of_block[iblk+1])
3160  {
3161  iblk++;
3162  }
3163  if (iblk >= (int) num_el_blk)
3164  {
3165  MFEM_ABORT("Sideset element does not exist");
3166  }
3167  loc_ind = glob_ind - start_of_block[iblk];
3168  int this_side = side_ss[i][j];
3169  int ielem = loc_ind*num_node_per_el;
3170 
3171  for (int k = 0; k < num_face_nodes; k++)
3172  {
3173  int inode;
3174  switch (cubit_element_type)
3175  {
3176  case (ELEMENT_TRI3):
3177  {
3178  inode = sideMapTri3[this_side-1][k];
3179  break;
3180  }
3181  case (ELEMENT_TRI6):
3182  {
3183  inode = sideMapTri6[this_side-1][k];
3184  break;
3185  }
3186  case (ELEMENT_QUAD4):
3187  {
3188  inode = sideMapQuad4[this_side-1][k];
3189  break;
3190  }
3191  case (ELEMENT_QUAD9):
3192  {
3193  inode = sideMapQuad9[this_side-1][k];
3194  break;
3195  }
3196  case (ELEMENT_TET4):
3197  {
3198  inode = sideMapTet4[this_side-1][k];
3199  break;
3200  }
3201  case (ELEMENT_TET10):
3202  {
3203  inode = sideMapTet10[this_side-1][k];
3204  break;
3205  }
3206  case (ELEMENT_HEX8):
3207  {
3208  inode = sideMapHex8[this_side-1][k];
3209  break;
3210  }
3211  case (ELEMENT_HEX27):
3212  {
3213  inode = sideMapHex27[this_side-1][k];
3214  break;
3215  }
3216  }
3217  ss_node_id[i][j*num_face_nodes+k] =
3218  elem_blk[iblk][ielem + inode - 1];
3219  }
3220  }
3221  }
3222 
3223  // we need another node ID mapping since MFEM needs contiguous vertex IDs
3224  std::vector<int> uniqueVertexID;
3225 
3226  for (int iblk = 0; iblk < (int) num_el_blk; iblk++)
3227  {
3228  for (int i = 0; i < (int) num_el_in_blk[iblk]; i++)
3229  {
3230  for (int j = 0; j < num_element_linear_nodes; j++)
3231  {
3232  uniqueVertexID.push_back(elem_blk[iblk][i*num_node_per_el + j]);
3233  }
3234  }
3235  }
3236  std::sort(uniqueVertexID.begin(), uniqueVertexID.end());
3237  std::vector<int>::iterator newEnd;
3238  newEnd = std::unique(uniqueVertexID.begin(), uniqueVertexID.end());
3239  uniqueVertexID.resize(std::distance(uniqueVertexID.begin(), newEnd));
3240 
3241  // OK at this point uniqueVertexID contains a list of all the nodes that are
3242  // actually used by the mesh, 1-based, and sorted. We need to invert this
3243  // list, the inverse is a map
3244 
3245  std::map<int,int> cubitToMFEMVertMap;
3246  for (int i = 0; i < (int) uniqueVertexID.size(); i++)
3247  {
3248  cubitToMFEMVertMap[uniqueVertexID[i]] = i+1;
3249  }
3250  MFEM_ASSERT(cubitToMFEMVertMap.size() == uniqueVertexID.size(),
3251  "This should never happen\n");
3252 
3253  // OK now load up the MFEM mesh structures
3254 
3255  // load up the vertices
3256 
3257  NumOfVertices = uniqueVertexID.size();
3258  vertices.SetSize(NumOfVertices);
3259  for (int i = 0; i < (int) uniqueVertexID.size(); i++)
3260  {
3261  vertices[i](0) = coordx[uniqueVertexID[i] - 1];
3262  vertices[i](1) = coordy[uniqueVertexID[i] - 1];
3263  if (Dim == 3)
3264  {
3265  vertices[i](2) = coordz[uniqueVertexID[i] - 1];
3266  }
3267  }
3268 
3269  NumOfElements = num_elem;
3270  elements.SetSize(num_elem);
3271  int elcount = 0;
3272  int renumberedVertID[8];
3273  for (int iblk = 0; iblk < (int) num_el_blk; iblk++)
3274  {
3275  int NumNodePerEl = num_node_per_el;
3276  for (int i = 0; i < (int) num_el_in_blk[iblk]; i++)
3277  {
3278  for (int j = 0; j < num_element_linear_nodes; j++)
3279  {
3280  renumberedVertID[j] =
3281  cubitToMFEMVertMap[elem_blk[iblk][i*NumNodePerEl+j]]-1;
3282  }
3283 
3284  switch (cubit_element_type)
3285  {
3286  case (ELEMENT_TRI3):
3287  case (ELEMENT_TRI6):
3288  {
3289  elements[elcount] = new Triangle(renumberedVertID,ebprop[iblk]);
3290  break;
3291  }
3292  case (ELEMENT_QUAD4):
3293  case (ELEMENT_QUAD9):
3294  {
3295  elements[elcount] = new Quadrilateral(renumberedVertID,ebprop[iblk]);
3296  break;
3297  }
3298  case (ELEMENT_TET4):
3299  case (ELEMENT_TET10):
3300  {
3301 #ifdef MFEM_USE_MEMALLOC
3302  elements[elcount] = TetMemory.Alloc();
3303  elements[elcount]->SetVertices(renumberedVertID);
3304  elements[elcount]->SetAttribute(ebprop[iblk]);
3305 #else
3306  elements[elcount] = new Tetrahedron(renumberedVertID,
3307  ebprop[iblk]);
3308 #endif
3309  break;
3310  }
3311  case (ELEMENT_HEX8):
3312  case (ELEMENT_HEX27):
3313  {
3314  elements[elcount] = new Hexahedron(renumberedVertID,ebprop[iblk]);
3315  break;
3316  }
3317  }
3318  elcount++;
3319  }
3320  }
3321 
3322  // load up the boundary elements
3323 
3324  NumOfBdrElements = 0;
3325  for (int iss = 0; iss < (int) num_side_sets; iss++)
3326  {
3327  NumOfBdrElements += num_side_in_ss[iss];
3328  }
3329  boundary.SetSize(NumOfBdrElements);
3330  int sidecount = 0;
3331  for (int iss = 0; iss < (int) num_side_sets; iss++)
3332  {
3333  for (int i = 0; i < (int) num_side_in_ss[iss]; i++)
3334  {
3335  for (int j = 0; j < num_face_linear_nodes; j++)
3336  {
3337  renumberedVertID[j] =
3338  cubitToMFEMVertMap[ss_node_id[iss][i*num_face_nodes+j]] - 1;
3339  }
3340  switch (cubit_face_type)
3341  {
3342  case (FACE_EDGE2):
3343  case (FACE_EDGE3):
3344  {
3345  boundary[sidecount] = new Segment(renumberedVertID,ssprop[iss]);
3346  break;
3347  }
3348  case (FACE_TRI3):
3349  case (FACE_TRI6):
3350  {
3351  boundary[sidecount] = new Triangle(renumberedVertID,ssprop[iss]);
3352  break;
3353  }
3354  case (FACE_QUAD4):
3355  case (FACE_QUAD9):
3356  {
3357  boundary[sidecount] = new Quadrilateral(renumberedVertID,ssprop[iss]);
3358  break;
3359  }
3360  }
3361  sidecount++;
3362  }
3363  }
3364 
3365  if (order == 2)
3366  {
3367  curved = 1;
3368  int *mymap = NULL;
3369 
3370  switch (cubit_element_type)
3371  {
3372  case (ELEMENT_TRI6):
3373  {
3374  mymap = (int *) mfemToGenesisTri6;
3375  break;
3376  }
3377  case (ELEMENT_QUAD9):
3378  {
3379  mymap = (int *) mfemToGenesisQuad9;
3380  break;
3381  }
3382  case (ELEMENT_TET10):
3383  {
3384  mymap = (int *) mfemToGenesisTet10;
3385  break;
3386  }
3387  case (ELEMENT_HEX27):
3388  {
3389  mymap = (int *) mfemToGenesisHex27;
3390  break;
3391  }
3392  case (ELEMENT_TRI3):
3393  case (ELEMENT_QUAD4):
3394  case (ELEMENT_TET4):
3395  case (ELEMENT_HEX8):
3396  {
3397  MFEM_ABORT("Something went wrong. Linear elements detected when order is 2.");
3398  break;
3399  }
3400  }
3401 
3402  FinalizeTopology();
3403 
3404  // Define quadratic FE space
3405  FiniteElementCollection *fec = new H1_FECollection(2,3);
3406  FiniteElementSpace *fes = new FiniteElementSpace(this, fec, Dim,
3407  Ordering::byVDIM);
3408  Nodes = new GridFunction(fes);
3409  Nodes->MakeOwner(fec); // Nodes will destroy 'fec' and 'fes'
3410  own_nodes = 1;
3411 
3412  // int nTotDofs = fes->GetNDofs();
3413  // int nTotVDofs = fes->GetVSize();
3414  // mfem::out << endl << "nTotDofs = " << nTotDofs << " nTotVDofs "
3415  // << nTotVDofs << endl << endl;
3416 
3417  for (int i = 0; i < NumOfElements; i++)
3418  {
3419  Array<int> dofs;
3420 
3421  fes->GetElementDofs(i, dofs);
3422  Array<int> vdofs;
3423  vdofs.SetSize(dofs.Size());
3424  for (int l = 0; l < dofs.Size(); l++) { vdofs[l] = dofs[l]; }
3425  fes->DofsToVDofs(vdofs);
3426  int iblk = 0;
3427  int loc_ind;
3428  while (iblk < (int) num_el_blk && i >= start_of_block[iblk+1]) { iblk++; }
3429  loc_ind = i - start_of_block[iblk];
3430  for (int j = 0; j < dofs.Size(); j++)
3431  {
3432  int point_id = elem_blk[iblk][loc_ind*num_node_per_el + mymap[j] - 1] - 1;
3433  (*Nodes)(vdofs[j]) = coordx[point_id];
3434  (*Nodes)(vdofs[j]+1) = coordy[point_id];
3435  if (Dim == 3)
3436  {
3437  (*Nodes)(vdofs[j]+2) = coordz[point_id];
3438  }
3439  }
3440  }
3441  }
3442 
3443  // clean up all netcdf stuff
3444 
3445  nc_close(ncid);
3446 
3447  for (int i = 0; i < (int) num_side_sets; i++)
3448  {
3449  delete [] elem_ss[i];
3450  delete [] side_ss[i];
3451  }
3452 
3453  delete [] elem_ss;
3454  delete [] side_ss;
3455  delete [] num_el_in_blk;
3456  delete [] num_side_in_ss;
3457  delete [] coordx;
3458  delete [] coordy;
3459  delete [] coordz;
3460 
3461  for (int i = 0; i < (int) num_el_blk; i++)
3462  {
3463  delete [] elem_blk[i];
3464  }
3465 
3466  delete [] elem_blk;
3467  delete [] start_of_block;
3468 
3469  for (int i = 0; i < (int) num_side_sets; i++)
3470  {
3471  delete [] ss_node_id[i];
3472  }
3473  delete [] ss_node_id;
3474  delete [] ebprop;
3475  delete [] ssprop;
3476 
3477 }
3478 #endif // #ifdef MFEM_USE_NETCDF
3479 
3480 } // namespace mfem
Abstract class for all finite elements.
Definition: fe.hpp:243
Arbitrary order non-uniform rational B-splines (NURBS) finite elements.
Definition: fe_coll.hpp:466
Vector bb_max
Definition: ex9.cpp:66
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:134
void Load(std::istream &in, int fmt=0)
Read an Array from the stream in using format fmt. The format fmt can be:
Definition: array.cpp:53
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
const Geometry::Type geom
Definition: ex1.cpp:40
T * GetData()
Returns the data.
Definition: array.hpp:108
int Size() const
Returns the size of the vector.
Definition: vector.hpp:190
void MakeOwner(FiniteElementCollection *fec_)
Make the GridFunction the owner of fec and fes.
Definition: gridfunc.hpp:118
Data type for vertex.
Definition: vertex.hpp:22
virtual void GetElementDofs(int elem, Array< int > &dofs) const
Returns indices of degrees of freedom of element &#39;elem&#39;.
Definition: fespace.cpp:2298
virtual void SetVertices(const int *ind)
Set the vertices according to the given input.
Data type quadrilateral element.
double * GetData() const
Return a pointer to the beginning of the Vector data.
Definition: vector.hpp:199
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:31
void DecodeBase64(const char *src, size_t len, std::vector< char > &buf)
Definition: binaryio.cpp:74
Mesh * Make2D(int nsteps, double rstep, double phi, double aspect, int order, bool sfc)
Definition: polar-nc.cpp:49
Class for standard nodal finite elements.
Definition: fe.hpp:706
void Load(std::istream **in, int np, int *dim)
Reads a vector from multiple files.
Definition: vector.cpp:57
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:746
Type
Constants for the classes derived from Element.
Definition: element.hpp:41
Data type triangle element.
Definition: triangle.hpp:23
size_t NumBase64Chars(size_t nbytes)
Definition: binaryio.cpp:103
const T * Read(const Memory< T > &mem, int size, bool on_dev=true)
Get a pointer for read access to mem with the mfem::Device&#39;s DeviceMemoryClass, if on_dev = true...
Definition: device.hpp:319
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:66
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:674
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
const Array< int > & GetLexicographicOrdering() const
Get an Array&lt;int&gt; that maps lexicographically ordered indices to the indices of the respective nodes/...
Definition: fe.hpp:780
double a
Definition: lissajous.cpp:41
bool StringCompare(const char *s1, const char *s2)
const char * VTKByteOrder()
Definition: vtk.cpp:590
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i&#39;th element in t...
Definition: fespace.cpp:2388
int index(int i, int j, int nx, int ny)
Definition: life.cpp:237
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:550
virtual void SetSpace(FiniteElementSpace *f)
Associate a new FiniteElementSpace with the GridFunction.
Definition: gridfunc.cpp:193
void filter_dos(std::string &line)
Check for, and remove, a trailing &#39;\r&#39; from and std::string.
Definition: text.hpp:45
Vector data type.
Definition: vector.hpp:60
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
void CreateVTKElementConnectivity(Array< int > &con, Geometry::Type geom, int ref)
Definition: vtk.cpp:489
Arbitrary order H1-conforming (continuous) finite elements.
Definition: fe_coll.hpp:216
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:285
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Definition: fespace.cpp:197