libMesh
Loading...
Searching...
No Matches
gmsh_io.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18// Local includes
19#include "libmesh/libmesh_config.h"
20#include "libmesh/libmesh_logging.h"
21#include "libmesh/boundary_info.h"
22#include "libmesh/bounding_box.h"
23#include "libmesh/elem.h"
24#include "libmesh/gmsh_io.h"
25#include "libmesh/mesh_base.h"
26#include "libmesh/int_range.h"
27#include "libmesh/utility.h" // map_find
28#include "libmesh/enum_to_string.h"
29
30// C++ includes
31#include <fstream>
32#include <set>
33#include <cstring> // std::memcpy
34#include <numeric>
35#include <unordered_map>
36#include <cstddef>
37
38namespace libMesh
39{
40
41// Initialize the static data member
43
44
45
46// Definition of the static function which constructs the ElementMaps object.
48{
49 // Object to be filled up
50 ElementMaps em;
51
52 // POINT (import only)
53 em.in.emplace(15, ElementDefinition(NODEELEM, 15, 0, 1));
54
55 // Add elements with trivial node mappings
56 em.add_def(ElementDefinition(EDGE2, 1, 1, 2));
57 em.add_def(ElementDefinition(EDGE3, 8, 1, 3));
58 em.add_def(ElementDefinition(TRI3, 2, 2, 3));
59 em.add_def(ElementDefinition(TRI6, 9, 2, 6));
60 em.add_def(ElementDefinition(QUAD4, 3, 2, 4));
61 em.add_def(ElementDefinition(QUAD8, 16, 2, 8));
62 em.add_def(ElementDefinition(QUAD9, 10, 2, 9));
63 em.add_def(ElementDefinition(HEX8, 5, 3, 8));
64 em.add_def(ElementDefinition(TET4, 4, 3, 4));
65 em.add_def(ElementDefinition(PRISM6, 6, 3, 6));
67
68 // Add elements with non-trivial node mappings
69
70 // HEX20
71 {
72 ElementDefinition eledef(HEX20, 17, 3, 20);
73 const unsigned int nodes[] = {0,1,2,3,4,5,6,7,8,11,12,9,13,10,14,15,16,19,17,18};
74 std::vector<unsigned int>(nodes, nodes+eledef.nnodes).swap(eledef.nodes); // swap trick
75 em.add_def(eledef);
76 }
77
78 // HEX27
79 {
80 ElementDefinition eledef(HEX27, 12, 3, 27);
81 const unsigned int nodes[] = {0,1,2,3,4,5,6,7,8,11,12,9,13,10,14,
82 15,16,19,17,18,20,21,24,22,23,25,26};
83 std::vector<unsigned int>(nodes, nodes+eledef.nnodes).swap(eledef.nodes); // swap trick
84 em.add_def(eledef);
85 }
86
87 // TET10
88 {
89 ElementDefinition eledef(TET10, 11, 3, 10);
90 const unsigned int nodes[] = {0,1,2,3,4,5,6,7,9,8};
91 std::vector<unsigned int>(nodes, nodes+eledef.nnodes).swap(eledef.nodes); // swap trick
92 em.add_def(eledef);
93 }
94
95 // PRISM15
96 {
97 ElementDefinition eledef(PRISM15, 18, 3, 15);
98 const unsigned int nodes[] = {0,1,2,3,4,5,6,8,9,7,10,11,12,14,13};
99 std::vector<unsigned int>(nodes, nodes+eledef.nnodes).swap(eledef.nodes); // swap trick
100 em.add_def(eledef);
101 }
102
103 // PRISM18
104 {
105 ElementDefinition eledef(PRISM18, 13, 3, 18);
106 const unsigned int nodes[] = {0,1,2,3,4,5,6,8,9,7,10,11,12,14,13,15,17,16};
107 std::vector<unsigned int>(nodes, nodes+eledef.nnodes).swap(eledef.nodes); // swap trick
108 em.add_def(eledef);
109 }
110
111 return em;
112}
113
114
115
118 _binary(false),
119 _write_lower_dimensional_elements(true)
120{
121}
122
123
124
128 _binary (false),
129 _write_lower_dimensional_elements(true)
130{
131}
132
133
134
136{
137 return _binary;
138}
139
140
141
146
147
148
149void GmshIO::read (const std::string & name)
150{
151 std::ifstream in (name.c_str());
152 this->read_mesh (in);
153}
154
155
156
157void GmshIO::read_mesh(std::istream & in)
158{
159 // This is a serial-only process for now;
160 // the Mesh should be read on processor 0 and
161 // broadcast later
162 libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().processor_id(), 0);
163
164 libmesh_assert(in.good());
165
166 // clear any data in the mesh
168 mesh.clear();
169
170 // some variables
171 int format=0, size=0;
172 Real version = 1.0;
173
174 // Keep track of lower-dimensional blocks which are not BCs, but
175 // actually blocks of lower-dimensional elements.
176 std::set<subdomain_id_type> lower_dimensional_blocks;
177
178 // Mapping from (physical id, physical dim) -> physical name.
179 // These can refer to either "sidesets" or "subdomains"; we need to
180 // wait until the Mesh has been read to know which is which. Note
181 // that we are using ptrdiff_t as the key here rather than
182 // subdomain_id_type or boundary_id_type, since at this point, it
183 // could be either.
184 std::map<std::pair<std::ptrdiff_t, unsigned>, std::string> gmsh_physicals;
185
186 // map to hold the node numbers for translation
187 // note the the nodes can be non-consecutive
188 std::map<unsigned int, unsigned int> nodetrans;
189
190 // Map from entity tag to physical id. The key is a pair with the first
191 // item being the dimension of the entity and the second item being
192 // the entity tag/id
193 std::map<std::pair<unsigned, int>, int> entity_to_physical_id;
194
195 // Map from entities to bounding boxes. The key is the same.
196 std::map<std::pair<unsigned, int>, BoundingBox> entity_to_bounding_box;
197
198 // For reading the file line by line
199 std::string s;
200
201 while (true)
202 {
203 // Try to read something. This may set EOF!
204 std::getline(in, s);
205
206 if (in)
207 {
208 // Process s...
209
210 if (s.find("$MeshFormat") == static_cast<std::string::size_type>(0))
211 {
212 in >> version >> format >> size;
213
214 // Some notes on gmsh mesh versions:
215 //
216 // Mesh version 2.0 goes back as far as I know. It's not explicitly
217 // mentioned here: http://www.geuz.org/gmsh/doc/VERSIONS.txt
218 //
219 // As of gmsh-2.4.0:
220 // bumped mesh version format to 2.1 (small change in the $PhysicalNames
221 // section, where the group dimension is now required);
222 // [Since we don't even parse the PhysicalNames section at the time
223 // of this writing, I don't think this change affects us.]
224 //
225 // Mesh version 2.2 tested by Manav Bhatia; no other
226 // libMesh code changes were required for support
227 //
228 // Mesh version 4.0 is a near complete rewrite of the previous mesh version
229 libmesh_error_msg_if(version < 2.0, "Error: Unknown msh file version " << version);
230 libmesh_error_msg_if(format, "Error: Unknown data format for mesh in Gmsh reader.");
231 }
232
233 // Read and process the "PhysicalNames" section.
234 else if (s.find("$PhysicalNames") == static_cast<std::string::size_type>(0))
235 {
236 // The lines in the PhysicalNames section should look like the following:
237 // 2 1 "frac" lower_dimensional_block
238 // 2 3 "top"
239 // 2 4 "bottom"
240 // 3 2 "volume"
241
242 // Read in the number of physical groups to expect in the file.
243 unsigned int num_physical_groups = 0;
244 in >> num_physical_groups;
245
246 // Read rest of line including newline character.
247 std::getline(in, s);
248
249 for (unsigned int i=0; i<num_physical_groups; ++i)
250 {
251 // Read an entire line of the PhysicalNames section.
252 std::getline(in, s);
253
254 // Use an istringstream to extract the physical
255 // dimension, physical id, and physical name from
256 // this line.
257 std::istringstream s_stream(s);
258 unsigned phys_dim;
259 int phys_id;
260 std::string phys_name;
261 s_stream >> phys_dim >> phys_id >> phys_name;
262
263 // Not sure if this is true for all Gmsh files, but
264 // my test file has quotes around the phys_name
265 // string. So let's erase any quotes now...
266 phys_name.erase(std::remove(phys_name.begin(), phys_name.end(), '"'), phys_name.end());
267
268 // Record this ID for later assignment of subdomain/sideset names.
269 gmsh_physicals[std::make_pair(phys_id, phys_dim)] = phys_name;
270
271 // If 's' also contains the libmesh-specific string
272 // "lower_dimensional_block", add this block ID to
273 // the list of blocks which are not boundary
274 // conditions.
275 if (s.find("lower_dimensional_block") != std::string::npos)
276 {
277 lower_dimensional_blocks.insert(restrict_int<subdomain_id_type>(phys_id));
278
279 // The user has explicitly told us that this
280 // block is a subdomain, so set that association
281 // in the Mesh.
282 mesh.set_subdomain_name(restrict_int<subdomain_id_type>(phys_id), phys_name);
283 }
284 }
285 }
286
287 else if (s.find("$Entities") == static_cast<std::string::size_type>(0))
288 {
289 if (version >= 4.0)
290 {
291 std::size_t num_point_entities, num_curve_entities, num_surface_entities, num_volume_entities;
292 in >> num_point_entities >> num_curve_entities >> num_surface_entities >> num_volume_entities;
293
294 for (std::size_t n = 0; n < num_point_entities; ++n)
295 {
296 int point_tag, physical_tag;
297 Real x, y, z;
298 std::size_t num_physical_tags;
299 in >> point_tag >> x >> y >> z >> num_physical_tags;
300
301 libmesh_error_msg_if(num_physical_tags > 1,
302 "Sorry, you cannot currently specify multiple subdomain or "
303 "boundary ids for a given geometric entity");
304
305 entity_to_bounding_box[std::make_pair(0, point_tag)] =
306 BoundingBox(Point(x,y,z),Point(x,y,z));
307
308 if (num_physical_tags)
309 {
310 in >> physical_tag;
311 entity_to_physical_id[std::make_pair(0, point_tag)] = physical_tag;
312 }
313 }
314 for (std::size_t n = 0; n < num_curve_entities; ++n)
315 {
316 int curve_tag, physical_tag;
317 Real minx, miny, minz, maxx, maxy, maxz;
318 std::size_t num_physical_tags;
319 in >> curve_tag >> minx >> miny >> minz >> maxx >> maxy >> maxz >> num_physical_tags;
320
321 libmesh_error_msg_if(num_physical_tags > 1,
322 "I don't believe that we can specify multiple subdomain or "
323 "boundary ids for a given geometric entity");
324
325 entity_to_bounding_box[std::make_pair(1, curve_tag)] =
326 BoundingBox(Point(minx,miny,minz),Point(maxx,maxy,maxz));
327
328 if (num_physical_tags)
329 {
330 in >> physical_tag;
331 entity_to_physical_id[std::make_pair(1, curve_tag)] = physical_tag;
332 }
333
334 // Read to end of line; this captures bounding information that we don't care about
335 std::getline(in, s);
336 }
337 for (std::size_t n = 0; n < num_surface_entities; ++n)
338 {
339 int surface_tag, physical_tag;
340 Real minx, miny, minz, maxx, maxy, maxz;
341 std::size_t num_physical_tags;
342 in >> surface_tag >> minx >> miny >> minz >> maxx >> maxy >> maxz >> num_physical_tags;
343
344 libmesh_error_msg_if(num_physical_tags > 1,
345 "I don't believe that we can specify multiple subdomain or "
346 "boundary ids for a given geometric entity");
347
348 entity_to_bounding_box[std::make_pair(2, surface_tag)] =
349 BoundingBox(Point(minx,miny,minz),Point(maxx,maxy,maxz));
350
351 if (num_physical_tags)
352 {
353 in >> physical_tag;
354 entity_to_physical_id[std::make_pair(2, surface_tag)] = physical_tag;
355 }
356
357 // Read to end of line; this captures bounding information that we don't care about
358 std::getline(in, s);
359 }
360 for (std::size_t n = 0; n < num_volume_entities; ++n)
361 {
362 int volume_tag, physical_tag;
363 Real minx, miny, minz, maxx, maxy, maxz;
364 std::size_t num_physical_tags;
365 in >> volume_tag >> minx >> miny >> minz >> maxx >> maxy >> maxz >> num_physical_tags;
366
367 libmesh_error_msg_if(num_physical_tags > 1,
368 "I don't believe that we can specify multiple subdomain or "
369 "boundary ids for a given geometric entity");
370
371 entity_to_bounding_box[std::make_pair(3, volume_tag)] =
372 BoundingBox(Point(minx,miny,minz),Point(maxx,maxy,maxz));
373
374 if (num_physical_tags)
375 {
376 in >> physical_tag;
377 entity_to_physical_id[std::make_pair(3, volume_tag)] = physical_tag;
378 }
379
380 // Read to end of line; this captures bounding information that we don't care about
381 std::getline(in, s);
382 }
383 // Read the $EndEntities
384 std::getline(in, s);
385 } // end if (version >= 4.0)
386
387 else
388 libmesh_error_msg("The Entities block was introduced in mesh version 4.0");
389 } // end if $Entities
390
391 // read the node block
392 else if (s.find("$NOD") == static_cast<std::string::size_type>(0) ||
393 s.find("$NOE") == static_cast<std::string::size_type>(0) ||
394 s.find("$Nodes") == static_cast<std::string::size_type>(0))
395 {
396 if (version < 4.0)
397 {
398 unsigned int num_nodes = 0;
399 in >> num_nodes;
400 mesh.reserve_nodes (num_nodes);
401
402 // read in the nodal coordinates and form points.
403 Real x, y, z;
404 unsigned int id;
405
406 // add the nodal coordinates to the mesh
407 for (unsigned int i=0; i<num_nodes; ++i)
408 {
409 in >> id >> x >> y >> z;
410 mesh.add_point (Point(x, y, z), i);
411 nodetrans[id] = i;
412 }
413 }
414 else
415 {
416 // Read numEntityBlocks line
417 std::size_t num_entities = 0, num_nodes = 0, min_node_tag, max_node_tag;
418 in >> num_entities >> num_nodes >> min_node_tag >> max_node_tag;
419
420 mesh.reserve_nodes(num_nodes);
421
422 std::size_t node_counter = 0;
423
424 // Now loop over entities
425 for (std::size_t i = 0; i < num_entities; ++i)
426 {
427 int entity_dim, entity_tag, parametric;
428 std::size_t num_nodes_in_block = 0;
429 in >> entity_dim >> entity_tag >> parametric >> num_nodes_in_block;
430 libmesh_error_msg_if(parametric, "We don't currently support reading parametric gmsh entities");
431
432 // Read the node tags/ids
433 std::size_t gmsh_id;
434 for (std::size_t n = 0; n < num_nodes_in_block; ++n)
435 {
436
437 in >> gmsh_id;
438 nodetrans[gmsh_id] = node_counter++;
439 }
440
441 // Read the node coordinates and add the nodes to the mesh
442 Real x, y, z;
443 for (std::size_t libmesh_id = node_counter - num_nodes_in_block;
444 libmesh_id < node_counter;
445 ++libmesh_id)
446 {
447 in >> x >> y >> z;
448 mesh.add_point(Point(x, y, z), libmesh_id);
449 }
450 }
451 }
452 // read the $ENDNOD delimiter
453 std::getline(in, s);
454 }
455
456 // Read the element block
457 else if (s.find("$ELM") == static_cast<std::string::size_type>(0) ||
458 s.find("$Elements") == static_cast<std::string::size_type>(0))
459 {
460 // Keep track of element dimensions seen
461 std::vector<unsigned> elem_dimensions_seen(3);
462
463 if (version < 4.0)
464 {
465 // For reading the number of elements and the node ids from the stream
466 unsigned int
467 num_elem = 0,
468 node_id = 0;
469
470 // read how many elements are there, and reserve space in the mesh
471 in >> num_elem;
472 mesh.reserve_elem (num_elem);
473
474 // As of version 2.2, the format for each element line is:
475 // elm-number elm-type number-of-tags < tag > ... node-number-list
476 // From the Gmsh docs:
477 // * the first tag is the number of the
478 // physical entity to which the element belongs
479 // * the second is the number of the elementary geometrical
480 // entity to which the element belongs
481 // * the third is the number of mesh partitions to which the element
482 // belongs
483 // * The rest of the tags are the partition ids (negative
484 // partition ids indicate ghost cells). A zero tag is
485 // equivalent to no tag. Gmsh and most codes using the
486 // MSH 2 format require at least the first two tags
487 // (physical and elementary tags).
488
489 // read the elements
490 for (unsigned int iel=0; iel<num_elem; ++iel)
491 {
492 unsigned int
493 id, type,
494 physical=1, elementary=1,
495 nnodes=0, ntags;
496
497 // Note: tag has to be an int because it could be negative,
498 // see above.
499 int tag;
500
501 if (version <= 1.0)
502 in >> id >> type >> physical >> elementary >> nnodes;
503
504 else
505 {
506 in >> id >> type >> ntags;
507
508 if (ntags > 2)
509 libmesh_do_once(libMesh::err << "Warning, ntags=" << ntags << ", but we currently only support reading 2 flags." << std::endl;);
510
511 for (unsigned int j = 0; j < ntags; j++)
512 {
513 in >> tag;
514 if (j == 0)
515 physical = tag;
516 else if (j == 1)
517 elementary = tag;
518 }
519 }
520
521 // Get a reference to the ElementDefinition, throw an error if not found.
522 const GmshIO::ElementDefinition & eletype =
523 libmesh_map_find(_element_maps.in, type);
524
525 // If we read nnodes, make sure it matches the number in eletype.nnodes
526 libmesh_error_msg_if(nnodes != 0 && nnodes != eletype.nnodes,
527 "nnodes = " << nnodes << " and eletype.nnodes = " << eletype.nnodes << " do not match.");
528
529 // Assign the value from the eletype object.
530 nnodes = eletype.nnodes;
531
532 // Don't add 0-dimensional "point" elements to the
533 // Mesh. They should *always* be treated as boundary
534 // "nodeset" data.
535 if (eletype.dim > 0)
536 {
537 // Record this element dimension as being "seen".
538 // We will treat all elements with dimension <
539 // max(dimension) as specifying boundary conditions,
540 // but we won't know what max_elem_dimension_seen is
541 // until we read the entire file.
542 elem_dimensions_seen[eletype.dim-1] = 1;
543
544 // Add the element to the mesh
545 {
546 Elem * elem =
547 mesh.add_elem(Elem::build_with_id(eletype.type, iel));
548
549 // Make sure that the libmesh element we added has nnodes nodes.
550 libmesh_error_msg_if(elem->n_nodes() != nnodes,
551 "Number of nodes for element "
552 << id
553 << " of type " << eletype.type
554 << " (Gmsh type " << type
555 << ") does not match Libmesh definition. "
556 << "I expected " << elem->n_nodes()
557 << " nodes, but got " << nnodes);
558
559 // Add node pointers to the elements.
560 // If there is a node translation table, use it.
561 if (eletype.nodes.size() > 0)
562 for (unsigned int i=0; i<nnodes; i++)
563 {
564 in >> node_id;
565 elem->set_node(eletype.nodes[i], mesh.node_ptr(nodetrans[node_id]));
566 }
567 else
568 {
569 for (unsigned int i=0; i<nnodes; i++)
570 {
571 in >> node_id;
572 elem->set_node(i, mesh.node_ptr(nodetrans[node_id]));
573 }
574 }
575
576 // Finally, set the subdomain ID to physical. If this is a lower-dimension element, this ID will
577 // eventually go into the Mesh's BoundaryInfo object.
578 elem->subdomain_id() = static_cast<subdomain_id_type>(physical);
579 }
580 }
581
582 // Handle 0-dimensional elements (points) by adding
583 // them to the BoundaryInfo object with
584 // boundary_id == physical.
585 else
586 {
587 // This seems like it should always be the same
588 // number as the 'id' we already read in on this
589 // line. At least it was in the example gmsh
590 // file I had...
591 in >> node_id;
593 (nodetrans[node_id],
594 static_cast<boundary_id_type>(physical));
595 }
596 } // element loop
597 } // end if (version < 4.0)
598
599 else
600 {
601 std::size_t num_entity_blocks = 0, num_elem = 0, min_element_tag, max_element_tag;
602
603 // Read entity information
604 in >> num_entity_blocks >> num_elem >> min_element_tag >> max_element_tag;
605
606 mesh.reserve_elem(num_elem);
607
608 std::size_t iel = 0;
609
610 // Loop over entity blocks
611 for (std::size_t i = 0; i < num_entity_blocks; ++i)
612 {
613 int entity_dim, entity_tag;
614 unsigned int element_type;
615 std::size_t num_elems_in_block = 0;
616 in >> entity_dim >> entity_tag >> element_type >> num_elems_in_block;
617
618 // Get a reference to the ElementDefinition
619 const GmshIO::ElementDefinition & eletype =
620 libmesh_map_find(_element_maps.in, element_type);
621
622 // Don't add 0-dimensional "point" elements to the
623 // Mesh. They should *always* be treated as boundary
624 // "nodeset" data.
625 if (eletype.dim > 0)
626 {
627 // Record this element dimension as being "seen".
628 // We will treat all elements with dimension <
629 // max(dimension) as specifying boundary conditions,
630 // but we won't know what max_elem_dimension_seen is
631 // until we read the entire file.
632 elem_dimensions_seen[eletype.dim-1] = 1;
633
634 // Loop over elements with dim > 0
635 for (std::size_t n = 0; n < num_elems_in_block; ++n)
636 {
637 Elem * elem =
638 mesh.add_elem(Elem::build_with_id(eletype.type, iel++));
639
640 std::size_t gmsh_element_id;
641 in >> gmsh_element_id;
642
643 // Make sure this element isn't somewhere
644 // unexpected
645
646 // A default bounding box is [inf,-inf] (empty);
647 // swap that and we get [-inf,inf] (everything)
648 BoundingBox expected_bounding_box;
649 std::swap(expected_bounding_box.min(),
650 expected_bounding_box.max());
651
652 if (auto it = entity_to_bounding_box.find
653 (std::make_pair(entity_dim, entity_tag));
654 it != entity_to_bounding_box.end())
655 expected_bounding_box = it->second;
656
657 // Get the remainder of the line that includes the nodes ids
658 std::getline(in, s);
659 std::istringstream is(s);
660 std::size_t local_node_counter = 0, gmsh_node_id;
661 while (is >> gmsh_node_id)
662 {
663 Node * node = mesh.node_ptr(nodetrans[gmsh_node_id]);
664
665 // Make sure the file is consistent about entity
666 // placement. Well, mostly consistent. We have
667 // files that claim a bounding box but still
668 // have points epsilon outside it.
669 libmesh_error_msg_if
670 (!expected_bounding_box.contains_point
671 (*node, /* abs */ 0, /* relative */ TOLERANCE),
672 "$Elements dim " << entity_dim << " element "
673 << gmsh_element_id << " (entity " << entity_tag
674 << ", " <<
675 Utility::enum_to_string(eletype.type) <<
676 ") has node at " << *static_cast<Node*>(node)
677 << "\n outside entity physical bounding box " <<
678 expected_bounding_box);
679
680 // Add node pointers to the elements.
681 // If there is a node translation table, use it.
682 if (eletype.nodes.size() > 0)
683 elem->set_node(eletype.nodes[local_node_counter++],
684 node);
685 else
686 elem->set_node(local_node_counter++, node);
687 }
688
689 // Make sure that the libmesh element we added has nnodes nodes.
690 libmesh_error_msg_if(elem->n_nodes() != local_node_counter,
691 "Number of nodes for element "
692 << gmsh_element_id
693 << " of type " << eletype.type
694 << " (Gmsh type " << element_type
695 << ") does not match Libmesh definition. "
696 << "I expected " << elem->n_nodes()
697 << " nodes, but got " << local_node_counter);
698
699 // Finally, set the subdomain ID to physical. If this is a lower-dimension element, this ID will
700 // eventually go into the Mesh's BoundaryInfo object.
701 elem->subdomain_id() = static_cast<subdomain_id_type>(
702 entity_to_physical_id[std::make_pair(entity_dim, entity_tag)]);
703
704 } // end for (loop over elements in entity block)
705 } // end if (eletype.dim > 0)
706
707 else
708 {
709 for (std::size_t n = 0; n < num_elems_in_block; ++n)
710 {
711 std::size_t gmsh_element_id, gmsh_node_id;
712 in >> gmsh_element_id;
713 in >> gmsh_node_id;
714
715 // Make sure the file is consistent about entity
716 // placement.
717
718 // A default bounding box is [inf,-inf] (empty);
719 // swap that and we get [-inf,inf] (everything)
720 BoundingBox expected_bounding_box;
721 std::swap(expected_bounding_box.min(),
722 expected_bounding_box.max());
723
724 if (auto it = entity_to_bounding_box.find
725 (std::make_pair(entity_dim, entity_tag));
726 it != entity_to_bounding_box.end())
727 expected_bounding_box = it->second;
728
729 Node * node = mesh.node_ptr(nodetrans[gmsh_node_id]);
730
731 // We'll accept *mostly* consistent. We have
732 // files that claim a bounding box but still have
733 // points epsilon outside it.
734 libmesh_error_msg_if
735 (!expected_bounding_box.contains_point
736 (*node, /* abs */ 0, /* relative */ TOLERANCE),
737 "$Elements dim " << entity_dim << " element "
738 << gmsh_element_id << " (entity " << entity_tag <<
739 ") has node at " << *static_cast<Node*>(node)
740 << "\n outside entity physical bounding box " <<
741 expected_bounding_box);
742
744 node,
745 static_cast<boundary_id_type>(entity_to_physical_id[
746 std::make_pair(entity_dim, entity_tag)]));
747 } // end for (loop over elements in entity block)
748 } // end if (eletype.dim == 0)
749 } // end for (loop over entity blocks)
750 } // end if (version >= 4.0)
751
752 // read the $ENDELM delimiter
753 std::getline(in, s);
754
755 // Record the max and min element dimension seen while reading the file.
756 unsigned char
757 max_elem_dimension_seen=1,
758 min_elem_dimension_seen=3;
759
760 for (auto i : index_range(elem_dimensions_seen))
761 if (elem_dimensions_seen[i])
762 {
763 // Debugging
764 // libMesh::out << "Seen elements of dimension " << i+1 << std::endl;
765 max_elem_dimension_seen =
766 std::max(max_elem_dimension_seen, cast_int<unsigned char>(i+1));
767 min_elem_dimension_seen =
768 std::min(min_elem_dimension_seen, cast_int<unsigned char>(i+1));
769 }
770
771 // Debugging:
772 // libMesh::out << "max_elem_dimension_seen=" << max_elem_dimension_seen << std::endl;
773 // libMesh::out << "min_elem_dimension_seen=" << min_elem_dimension_seen << std::endl;
774
775
776 // How many different element dimensions did we see while reading from file?
777 unsigned n_dims_seen = std::accumulate(elem_dimensions_seen.begin(),
778 elem_dimensions_seen.end(),
779 static_cast<unsigned>(0),
780 std::plus<unsigned>());
781
782
783 // Set mesh_dimension based on the largest element dimension seen.
784 mesh.set_mesh_dimension(max_elem_dimension_seen);
785
786 // Now that we know the maximum element dimension seen,
787 // we know whether the physical names are subdomain
788 // names or sideset names.
789 for (const auto & pr : gmsh_physicals)
790 {
791 // Extract data
792 auto [phys_id, phys_dim] = pr.first;
793 const std::string & phys_name = pr.second;
794
795 // If the physical's dimension matches the largest
796 // dimension we've seen, it's a subdomain name.
797 if (phys_dim == max_elem_dimension_seen)
798 mesh.set_subdomain_name(restrict_int<subdomain_id_type>(phys_id), phys_name);
799
800 // If it's zero-dimensional then it's a nodeset
801 else if (phys_dim == 0)
802 mesh.get_boundary_info().nodeset_name(cast_int<boundary_id_type>(phys_id)) = phys_name;
803
804 // Otherwise, if it's not a lower-dimensional
805 // block, it's a sideset name.
806 else if (phys_dim < max_elem_dimension_seen &&
807 !lower_dimensional_blocks.count(cast_int<boundary_id_type>(phys_id)))
808 mesh.get_boundary_info().sideset_name(cast_int<boundary_id_type>(phys_id)) = phys_name;
809 }
810
811 if (n_dims_seen > 1)
812 {
813 // Store lower-dimensional elements in a map sorted
814 // by Elem::key(). We use a multimap for two reasons:
815 // 1.) The hash function is not guaranteed to be
816 // unique, so different lower-dimensional elements
817 // could theoretically hash to the same value,
818 // although this is pretty unlikely.
819 // 2.) The Gmsh file may contain multiple
820 // lower-dimensional elements for a single side in
821 // order to implement multiple boundary ids for a
822 // single side. These lower-dimensional elements
823 // will all hash to the same value, and we need to
824 // be able to store all of them.
825 typedef std::unordered_multimap<dof_id_type, Elem *> provide_container_t;
826 provide_container_t provide_bcs;
827
828 // 1st loop over active elements - get info about lower-dimensional elements.
829 for (auto & elem : mesh.active_element_ptr_range())
830 if (elem->dim() < max_elem_dimension_seen &&
831 !lower_dimensional_blocks.count(elem->subdomain_id()))
832 {
833 // To be consistent with the previous
834 // GmshIO behavior, add all the
835 // lower-dimensional elements' nodes to
836 // the Mesh's BoundaryInfo object with the
837 // lower-dimensional element's subdomain
838 // ID.
839 for (auto n : elem->node_index_range())
840 mesh.get_boundary_info().add_node(elem->node_id(n),
841 elem->subdomain_id());
842
843 // Store this elem in a quickly-searchable
844 // container to use it to assign boundary
845 // conditions later.
846 provide_bcs.emplace(elem->key(), elem);
847 }
848
849 // 2nd loop over active elements - use lower dimensional element data to set BCs for higher dimensional elements
850 for (auto & elem : mesh.active_element_ptr_range())
851 if (elem->dim() == max_elem_dimension_seen)
852 {
853 // This is a max-dimension element that
854 // may require BCs. For each of its
855 // sides, including internal sides, we'll
856 // see if one more more lower-dimensional elements
857 // provides boundary information for it.
858 // Note that we have not yet called
859 // find_neighbors(), so we can't use
860 // elem->neighbor(sn) in this algorithm...
861 for (auto sn : elem->side_index_range())
862 for (const auto & pr : as_range(provide_bcs.equal_range(elem->key(sn))))
863 {
864 // For each side side in the provide_bcs multimap...
865 // Construct the side for hash verification.
866 std::unique_ptr<Elem> side (elem->build_side_ptr(sn));
867
868 // Construct the lower-dimensional element to compare to the side.
869 Elem * lower_dim_elem = pr.second;
870
871 // This was a hash, so it might not be perfect. Let's verify...
872 if (*lower_dim_elem == *side)
873 {
874 // Add the lower-dimensional
875 // element's subdomain_id as a
876 // boundary_id for the
877 // higher-dimensional element.
878 boundary_id_type bid = cast_int<boundary_id_type>(lower_dim_elem->subdomain_id());
879 mesh.get_boundary_info().add_side(elem, sn, bid);
880 }
881 }
882 }
883
884 // 3rd loop over active elements - Remove the lower-dimensional elements
885 for (auto & elem : mesh.active_element_ptr_range())
886 if (elem->dim() < max_elem_dimension_seen &&
887 !lower_dimensional_blocks.count(elem->subdomain_id()))
888 mesh.delete_elem(elem);
889 } // end if (n_dims_seen > 1)
890 } // if $ELM
891
892 continue;
893 } // if (in)
894
895
896 // If !in, check to see if EOF was set. If so, break out
897 // of while loop.
898 if (in.eof())
899 break;
900
901 // If !in and !in.eof(), stream is in a bad state!
902 libmesh_error_msg("Stream is bad! Perhaps the file does not exist?");
903
904 } // while true
905}
906
907
908
909void GmshIO::write (const std::string & name)
910{
911 if (MeshOutput<MeshBase>::mesh().processor_id() == 0)
912 {
913 // Open the output file stream
914 std::ofstream out_stream (name.c_str());
915
916 // Make sure it opened correctly
917 if (!out_stream.good())
918 libmesh_file_error(name.c_str());
919
920 this->write_mesh (out_stream);
921 }
922}
923
924
925
926void GmshIO::write_nodal_data (const std::string & fname,
927 const std::vector<Number> & soln,
928 const std::vector<std::string> & names)
929{
930 LOG_SCOPE("write_nodal_data()", "GmshIO");
931
932 if (MeshOutput<MeshBase>::mesh().processor_id() == 0)
933 this->write_post (fname, &soln, &names);
934}
935
936
937
938void GmshIO::write_mesh (std::ostream & out_stream)
939{
940 // Be sure that the stream is valid.
941 libmesh_assert (out_stream.good());
942
943 // Get a const reference to the mesh
945
946 // If requested, write out lower-dimensional elements for
947 // element-side-based boundary conditions.
948 std::size_t n_boundary_faces = 0;
950 n_boundary_faces = mesh.get_boundary_info().n_boundary_conds();
951
952 // Note: we are using version 2.0 of the gmsh output format.
953
954 // Write the file header.
955 out_stream << "$MeshFormat\n";
956 out_stream << "2.0 0 " << sizeof(Real) << '\n';
957 out_stream << "$EndMeshFormat\n";
958
959 // write the nodes in (n x y z) format
960 out_stream << "$Nodes\n";
961 out_stream << mesh.n_nodes() << '\n';
962
963 for (auto v : make_range(mesh.n_nodes()))
964 out_stream << mesh.node_ref(v).id()+1 << " "
965 << mesh.node_ref(v)(0) << " "
966 << mesh.node_ref(v)(1) << " "
967 << mesh.node_ref(v)(2) << '\n';
968 out_stream << "$EndNodes\n";
969
970 {
971 // write the connectivity
972 out_stream << "$Elements\n";
973 out_stream << mesh.n_active_elem() + n_boundary_faces << '\n';
974
975 // loop over the elements
976 for (const auto & elem : mesh.active_element_ptr_range())
977 {
978 // Get a reference to the ElementDefinition object
979 const ElementDefinition & eletype =
980 libmesh_map_find(_element_maps.out, elem->type());
981
982 // The element mapper better not require any more nodes
983 // than are present in the current element!
984 libmesh_assert_less_equal (eletype.nodes.size(), elem->n_nodes());
985
986 // elements ids are 1 based in Gmsh
987 out_stream << elem->id()+1 << " ";
988 // element type
989 out_stream << eletype.gmsh_type;
990
991 // write the number of tags (3) and their values:
992 // 1 (physical entity)
993 // 2 (geometric entity)
994 // 3 (partition entity)
995 out_stream << " 3 "
996 << static_cast<unsigned int>(elem->subdomain_id())
997 << " 0 "
998 << elem->processor_id()+1
999 << " ";
1000
1001 // if there is a node translation table, use it
1002 if (eletype.nodes.size() > 0)
1003 for (auto i : elem->node_index_range())
1004 out_stream << elem->node_id(eletype.nodes[i])+1 << " "; // gmsh is 1-based
1005 // otherwise keep the same node order
1006 else
1007 for (auto i : elem->node_index_range())
1008 out_stream << elem->node_id(i)+1 << " "; // gmsh is 1-based
1009 out_stream << "\n";
1010 } // element loop
1011 }
1012
1013 {
1014 // A counter for writing surface elements to the Gmsh file
1015 // sequentially. We start numbering them with a number strictly
1016 // larger than the largest element ID in the mesh. Note: the
1017 // MeshBase docs say "greater than or equal to" the maximum
1018 // element id in the mesh, so technically we might need a +1 here,
1019 // but all of the implementations return an ID strictly greater
1020 // than the largest element ID in the Mesh.
1021 unsigned int e_id = mesh.max_elem_id();
1022
1023 // loop over the elements, writing out boundary faces
1024 if (n_boundary_faces)
1025 {
1026 // Build a list of (elem, side, bc) tuples.
1027 auto bc_triples = mesh.get_boundary_info().build_side_list();
1028
1029 // Loop over these lists, writing data to the file.
1030 for (const auto & t : bc_triples)
1031 {
1032 const Elem & elem = mesh.elem_ref(std::get<0>(t));
1033
1034 std::unique_ptr<const Elem> side = elem.build_side_ptr(std::get<1>(t));
1035
1036 // consult the export element table
1037 const GmshIO::ElementDefinition & eletype =
1038 libmesh_map_find(_element_maps.out, side->type());
1039
1040 // The element mapper better not require any more nodes
1041 // than are present in the current element!
1042 libmesh_assert_less_equal (eletype.nodes.size(), side->n_nodes());
1043
1044 // elements ids are 1-based in Gmsh
1045 out_stream << e_id+1 << " ";
1046
1047 // element type
1048 out_stream << eletype.gmsh_type;
1049
1050 // write the number of tags:
1051 // 1 (physical entity)
1052 // 2 (geometric entity)
1053 // 3 (partition entity)
1054 out_stream << " 3 "
1055 << std::get<2>(t)
1056 << " 0 "
1057 << elem.processor_id()+1
1058 << " ";
1059
1060 // if there is a node translation table, use it
1061 if (eletype.nodes.size() > 0)
1062 for (auto i : side->node_index_range())
1063 out_stream << side->node_id(eletype.nodes[i])+1 << " "; // gmsh is 1-based
1064
1065 // otherwise keep the same node order
1066 else
1067 for (auto i : side->node_index_range())
1068 out_stream << side->node_id(i)+1 << " "; // gmsh is 1-based
1069
1070 // Go to the next line
1071 out_stream << "\n";
1072
1073 // increment this index too...
1074 ++e_id;
1075 }
1076 }
1077
1078 out_stream << "$EndElements\n";
1079 }
1080}
1081
1082
1083
1084void GmshIO::write_post (const std::string & fname,
1085 const std::vector<Number> * v,
1086 const std::vector<std::string> * solution_names)
1087{
1088
1089 // Should only do this on processor 0!
1090 libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().processor_id(), 0);
1091
1092 // Create an output stream
1093 std::ofstream out_stream(fname.c_str());
1094
1095 // Make sure it opened correctly
1096 if (!out_stream.good())
1097 libmesh_file_error(fname.c_str());
1098
1099 // create a character buffer
1100 char buf[80];
1101
1102 // Get a constant reference to the mesh.
1104
1105 // write the data
1106 if ((solution_names != nullptr) && (v != nullptr))
1107 {
1108 const unsigned int n_vars =
1109 cast_int<unsigned int>(solution_names->size());
1110
1111 if (!(v->size() == mesh.n_nodes()*n_vars))
1112 libMesh::err << "ERROR: v->size()=" << v->size()
1113 << ", mesh.n_nodes()=" << mesh.n_nodes()
1114 << ", n_vars=" << n_vars
1115 << ", mesh.n_nodes()*n_vars=" << mesh.n_nodes()*n_vars
1116 << "\n";
1117
1118 libmesh_assert_equal_to (v->size(), mesh.n_nodes()*n_vars);
1119
1120 // write the header
1121 out_stream << "$PostFormat\n";
1122 if (this->binary())
1123 out_stream << "1.2 1 " << sizeof(double) << "\n";
1124 else
1125 out_stream << "1.2 0 " << sizeof(double) << "\n";
1126 out_stream << "$EndPostFormat\n";
1127
1128 // Loop over the elements to see how much of each type there are
1129 unsigned int n_points=0, n_lines=0, n_triangles=0, n_quadrangles=0,
1130 n_tetrahedra=0, n_hexahedra=0, n_prisms=0, n_pyramids=0;
1131 unsigned int n_scalar=0, n_vector=0, n_tensor=0;
1132 unsigned int nb_text2d=0, nb_text2d_chars=0, nb_text3d=0, nb_text3d_chars=0;
1133
1134 {
1135 for (const auto & elem : mesh.active_element_ptr_range())
1136 {
1137 const ElemType elemtype = elem->type();
1138
1139 switch (elemtype)
1140 {
1141 case EDGE2:
1142 case EDGE3:
1143 case EDGE4:
1144 {
1145 n_lines += 1;
1146 break;
1147 }
1148 case TRI3:
1149 case TRI6:
1150 {
1151 n_triangles += 1;
1152 break;
1153 }
1154 case QUAD4:
1155 case QUAD8:
1156 case QUAD9:
1157 {
1158 n_quadrangles += 1;
1159 break;
1160 }
1161 case TET4:
1162 case TET10:
1163 {
1164 n_tetrahedra += 1;
1165 break;
1166 }
1167 case HEX8:
1168 case HEX20:
1169 case HEX27:
1170 {
1171 n_hexahedra += 1;
1172 break;
1173 }
1174 case PRISM6:
1175 case PRISM15:
1176 case PRISM18:
1177 {
1178 n_prisms += 1;
1179 break;
1180 }
1181 case PYRAMID5:
1182 {
1183 n_pyramids += 1;
1184 break;
1185 }
1186 default:
1187 libmesh_error_msg("ERROR: Nonexistent element type " << Utility::enum_to_string(elem->type()));
1188 }
1189 }
1190 }
1191
1192 // create a view for each variable
1193 for (unsigned int ivar=0; ivar < n_vars; ivar++)
1194 {
1195 std::string varname = (*solution_names)[ivar];
1196
1197 // at the moment, we just write out scalar quantities
1198 // later this should be made configurable through
1199 // options to the writer class
1200 n_scalar = 1;
1201
1202 // write the variable as a view, and the number of time steps
1203 out_stream << "$View\n" << varname << " " << 1 << "\n";
1204
1205 // write how many of each geometry type are written
1206 out_stream << n_points * n_scalar << " "
1207 << n_points * n_vector << " "
1208 << n_points * n_tensor << " "
1209 << n_lines * n_scalar << " "
1210 << n_lines * n_vector << " "
1211 << n_lines * n_tensor << " "
1212 << n_triangles * n_scalar << " "
1213 << n_triangles * n_vector << " "
1214 << n_triangles * n_tensor << " "
1215 << n_quadrangles * n_scalar << " "
1216 << n_quadrangles * n_vector << " "
1217 << n_quadrangles * n_tensor << " "
1218 << n_tetrahedra * n_scalar << " "
1219 << n_tetrahedra * n_vector << " "
1220 << n_tetrahedra * n_tensor << " "
1221 << n_hexahedra * n_scalar << " "
1222 << n_hexahedra * n_vector << " "
1223 << n_hexahedra * n_tensor << " "
1224 << n_prisms * n_scalar << " "
1225 << n_prisms * n_vector << " "
1226 << n_prisms * n_tensor << " "
1227 << n_pyramids * n_scalar << " "
1228 << n_pyramids * n_vector << " "
1229 << n_pyramids * n_tensor << " "
1230 << nb_text2d << " "
1231 << nb_text2d_chars << " "
1232 << nb_text3d << " "
1233 << nb_text3d_chars << "\n";
1234
1235 // if binary, write a marker to identify the endianness of the file
1236 if (this->binary())
1237 {
1238 const int one = 1;
1239 std::memcpy(buf, &one, sizeof(int));
1240 out_stream.write(buf, sizeof(int));
1241 }
1242
1243 // the time steps (there is just 1 at the moment)
1244 if (this->binary())
1245 {
1246 double one = 1;
1247 std::memcpy(buf, &one, sizeof(double));
1248 out_stream.write(buf, sizeof(double));
1249 }
1250 else
1251 out_stream << "1\n";
1252
1253 // Loop over the elements and write out the data
1254 for (const auto & elem : mesh.active_element_ptr_range())
1255 {
1256 const unsigned int nv = elem->n_vertices();
1257 // this is quite crappy, but I did not invent that file format!
1258 for (unsigned int d=0; d<3; d++) // loop over the dimensions
1259 {
1260 for (unsigned int n=0; n < nv; n++) // loop over vertices
1261 {
1262 const Point & vertex = elem->point(n);
1263 if (this->binary())
1264 {
1265#if defined(LIBMESH_DEFAULT_TRIPLE_PRECISION) || defined(LIBMESH_DEFAULT_QUADRUPLE_PRECISION)
1266 libmesh_warning("Gmsh binary writes use only double precision!");
1267#endif
1268 double tmp = double(vertex(d));
1269 std::memcpy(buf, &tmp, sizeof(double));
1270 out_stream.write(reinterpret_cast<char *>(buf), sizeof(double));
1271 }
1272 else
1273 out_stream << vertex(d) << " ";
1274 }
1275 if (!this->binary())
1276 out_stream << "\n";
1277 }
1278
1279 // now finally write out the data
1280 for (unsigned int i=0; i < nv; i++) // loop over vertices
1281 if (this->binary())
1282 {
1283#ifdef LIBMESH_USE_COMPLEX_NUMBERS
1284 libMesh::out << "WARNING: Gmsh::write_post does not fully support "
1285 << "complex numbers. Will only write the real part of "
1286 << "variable " << varname << std::endl;
1287#endif
1288 double tmp = double(libmesh_real((*v)[elem->node_id(i)*n_vars + ivar]));
1289 std::memcpy(buf, &tmp, sizeof(double));
1290 out_stream.write(reinterpret_cast<char *>(buf), sizeof(double));
1291 }
1292 else
1293 {
1294#ifdef LIBMESH_USE_COMPLEX_NUMBERS
1295 libMesh::out << "WARNING: Gmsh::write_post does not fully support "
1296 << "complex numbers. Will only write the real part of "
1297 << "variable " << varname << std::endl;
1298#endif
1299 out_stream << libmesh_real((*v)[elem->node_id(i)*n_vars + ivar]) << "\n";
1300 }
1301 }
1302 if (this->binary())
1303 out_stream << "\n";
1304 out_stream << "$EndView\n";
1305
1306 } // end variable loop (writing the views)
1307 }
1308}
1309
1310} // namespace libMesh
unsigned int n_vars
std::string & sideset_name(boundary_id_type id)
std::vector< BCTuple > build_side_list(BCTupleSortBy sort_by=BCTupleSortBy::ELEM_ID) const
std::size_t n_boundary_conds() const
std::string & nodeset_name(boundary_id_type id)
void add_node(const Node *node, const boundary_id_type id)
Add Node node with boundary id id to the boundary information data structures.
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
Add side side of element number elem with boundary id id to the boundary information data structure.
Defines a Cartesian bounding box by the two corner extremum.
const Point & max() const
const Point & min() const
bool contains_point(const Point &) const
processor_id_type processor_id() const
Definition dof_object.h:881
dof_id_type id() const
Definition dof_object.h:819
This is the base class from which all geometric element types are derived.
Definition elem.h:96
virtual Node *& set_node(const unsigned int i)
Definition elem.h:2567
static std::unique_ptr< Elem > build_with_id(const ElemType type, dof_id_type id)
Calls the build() method above with a nullptr parent, and additionally sets the newly-created Elem's ...
Definition elem.C:556
virtual unsigned int n_nodes() const =0
subdomain_id_type subdomain_id() const
Definition elem.h:2591
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i)=0
bool & binary()
Flag indicating whether or not to write a binary file.
Definition gmsh_io.C:135
bool & write_lower_dimensional_elements()
Access to the flag which controls whether boundary elements are written to the Mesh file.
Definition gmsh_io.C:142
virtual void write(const std::string &name) override
This method implements writing a mesh to a specified file in the Gmsh *.msh format.
Definition gmsh_io.C:909
void write_mesh(std::ostream &out)
This method implements writing a mesh to a specified file.
Definition gmsh_io.C:938
void write_post(const std::string &, const std::vector< Number > *=nullptr, const std::vector< std::string > *=nullptr)
This method implements writing a mesh with nodal data to a specified file where the nodal data and va...
Definition gmsh_io.C:1084
void read_mesh(std::istream &in)
Implementation of the read() function.
Definition gmsh_io.C:157
bool _binary
Flag to write binary data.
Definition gmsh_io.h:149
virtual void read(const std::string &name) override
Reads in a mesh in the Gmsh *.msh format from the ASCII file given by name.
Definition gmsh_io.C:149
bool _write_lower_dimensional_elements
If true, lower-dimensional elements based on the boundary conditions get written to the output file.
Definition gmsh_io.h:155
virtual void write_nodal_data(const std::string &, const std::vector< Number > &, const std::vector< std::string > &) override
This method implements writing a mesh with nodal data to a specified file where the nodal data and va...
Definition gmsh_io.C:926
GmshIO(MeshBase &mesh)
Constructor.
Definition gmsh_io.C:125
static ElementMaps _element_maps
A static ElementMaps object that is built statically and used by all instances of this class.
Definition gmsh_io.h:200
static ElementMaps build_element_maps()
A static function used to construct the _element_maps struct, statically.
Definition gmsh_io.C:47
This is the MeshBase class.
Definition mesh_base.h:81
void set_subdomain_name(subdomain_id_type id, const std::string &name, bool synchronous=false)
Sets the name for the provided id.
Definition mesh_base.C:1914
virtual const Node & node_ref(const dof_id_type i) const
Definition mesh_base.h:745
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition mesh_base.h:170
virtual const Node * node_ptr(const dof_id_type i) const =0
virtual dof_id_type n_nodes() const =0
virtual void delete_elem(Elem *e)=0
Removes element e from the mesh.
void set_mesh_dimension(unsigned char d)
Resets the logical dimension of the mesh.
Definition mesh_base.h:423
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
Add a new Node at Point p to the end of the vertex array, with processor_id procid.
virtual dof_id_type max_elem_id() const =0
virtual void clear()
Deletes all the element and node data that is currently stored.
Definition mesh_base.C:1036
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
virtual const Elem & elem_ref(const dof_id_type i) const
Definition mesh_base.h:788
virtual void reserve_elem(const dof_id_type ne)=0
Reserves space for a known number of elements.
virtual dof_id_type n_active_elem() const =0
virtual void reserve_nodes(const dof_id_type nn)=0
Reserves space for a known number of nodes.
This class defines an abstract interface for Mesh input.
Definition mesh_input.h:49
This class defines an abstract interface for Mesh output.
Definition mesh_output.h:54
const MT & mesh() const
A Node is like a Point, but with more information.
Definition node.h:55
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
MeshBase & mesh
std::string enum_to_string(const T e)
The libMesh namespace provides an interface to certain functionality in the library.
OStreamProxy err
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
Helper function that allows us to treat a homogenous pair as a range.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition int_range.h:153
ElemType
Defines an enum for geometric element types.
int8_t boundary_id_type
Definition id_types.h:51
T libmesh_real(T a)
libmesh_assert(ctx)
OStreamProxy out
PetscErrorCode PetscInt const PetscInt IS * is
static constexpr Real TOLERANCE
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition int_range.h:176
Defines mapping from libMesh element types to Gmsh element types or vice-versa.
Definition gmsh_io.h:161
std::vector< unsigned int > nodes
Definition gmsh_io.h:176
struct which holds a map from Gmsh to libMesh element numberings and vice-versa.
Definition gmsh_io.h:184
std::map< ElemType, ElementDefinition > out
Definition gmsh_io.h:192
std::map< unsigned int, ElementDefinition > in
Definition gmsh_io.h:193
void add_def(const ElementDefinition &eledef)
Definition gmsh_io.h:186