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