deal.II version GIT relicensing-2432-g84ca6043fc 2025-01-24 14:50:00+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
grid_in.cc
Go to the documentation of this file.
1// ------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4// Copyright (C) 1999 - 2024 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Part of the source code is dual licensed under Apache-2.0 WITH
9// LLVM-exception OR LGPL-2.1-or-later. Detailed license information
10// governing the source code and code contributions can be found in
11// LICENSE.md and CONTRIBUTING.md at the top level directory of deal.II.
12//
13// ------------------------------------------------------------------------
14
15
19
22#include <deal.II/grid/tria.h>
23
24#include <boost/algorithm/string.hpp>
25#include <boost/archive/binary_iarchive.hpp>
26#include <boost/io/ios_state.hpp>
27#include <boost/property_tree/ptree.hpp>
28#include <boost/property_tree/xml_parser.hpp>
29#include <boost/serialization/serialization.hpp>
30
31#ifdef DEAL_II_GMSH_WITH_API
32# include <gmsh.h>
33#endif
34
35#include <algorithm>
36#include <cctype>
37#include <filesystem>
38#include <fstream>
39#include <limits>
40#include <map>
41
42#ifdef DEAL_II_WITH_ASSIMP
43# include <assimp/Importer.hpp> // C++ importer interface
44# include <assimp/postprocess.h> // Post processing flags
45# include <assimp/scene.h> // Output data structure
46#endif
47
48#ifdef DEAL_II_TRILINOS_WITH_SEACAS
49# include <exodusII.h>
50#endif
51
52
54
55
56namespace
57{
75 template <int spacedim>
76 void
77 assign_1d_boundary_ids(
78 const std::vector<std::pair<Point<spacedim>, types::boundary_id>>
79 &boundary_ids,
81 {
82 for (auto &cell : triangulation.active_cell_iterators())
83 for (const unsigned int face_no : ReferenceCells::Line.face_indices())
84 if (cell->face(face_no)->at_boundary())
85 for (const auto &pair : boundary_ids)
86 if (cell->face(face_no)->vertex(0) == pair.first)
87 {
88 cell->face(face_no)->set_boundary_id(pair.second);
89 break;
90 }
91 }
92
93
94 template <int dim, int spacedim>
95 void
96 assign_1d_boundary_ids(
97 const std::vector<std::pair<Point<spacedim>, types::boundary_id>> &,
99 {
100 // we shouldn't get here since boundary ids are not assigned to
101 // vertices except in 1d
102 Assert(dim != 1, ExcInternalError());
103 }
104
108 template <int dim, int spacedim>
109 void
110 apply_grid_fixup_functions(std::vector<Point<spacedim>> &vertices,
111 std::vector<CellData<dim>> &cells,
112 SubCellData &subcelldata)
113 {
114 // check that no forbidden arrays are used
115 Assert(subcelldata.check_consistency(dim), ExcInternalError());
116 const auto n_hypercube_vertices =
117 ReferenceCells::get_hypercube<dim>().n_vertices();
118 bool is_only_hypercube = true;
119 for (const CellData<dim> &cell : cells)
120 if (cell.vertices.size() != n_hypercube_vertices)
121 {
122 is_only_hypercube = false;
123 break;
124 }
125
126 GridTools::delete_unused_vertices(vertices, cells, subcelldata);
127 if (dim == spacedim)
129
130 if (is_only_hypercube)
132 }
133} // namespace
134
135template <int dim, int spacedim>
137 : tria(nullptr, typeid(*this).name())
138 , default_format(ucd)
139{}
140
141
142
143template <int dim, int spacedim>
145 : tria(&t, typeid(*this).name())
146 , default_format(ucd)
147{}
148
149
150
151template <int dim, int spacedim>
152void
157
158
159
160template <int dim, int spacedim>
161void
163{
164 std::string line;
165
166 // verify that the third and fourth lines match
167 // expectations. the first line is not checked to allow use of
168 // different vtk versions and the second line of the file may
169 // essentially be anything the author of the file chose to
170 // identify what's in there, so we just ensure that we can read it.
171 {
172 std::string text[4];
173 text[0] = "# vtk DataFile Version 3.0";
174 text[1] = "****";
175 text[2] = "ASCII";
176 text[3] = "DATASET UNSTRUCTURED_GRID";
177
178 for (unsigned int i = 0; i < 4; ++i)
179 {
180 getline(in, line);
181 if (i == 2 || i == 3)
183 line.compare(text[i]) == 0,
185 std::string(
186 "While reading VTK file, failed to find a header line with text <") +
187 text[i] + ">"));
188 }
189 }
190
191 //-----------------Declaring storage and mappings------------------
192
193 std::vector<Point<spacedim>> vertices;
194 std::vector<CellData<dim>> cells;
195 SubCellData subcelldata;
196
197 std::string keyword;
198
199 in >> keyword;
200
201 //----------------Processing the POINTS section---------------
202
203 if (keyword == "POINTS")
204 {
205 unsigned int n_vertices;
206 in >> n_vertices;
207
208 in >> keyword; // float, double, int, char, etc.
209
210 for (unsigned int vertex = 0; vertex < n_vertices; ++vertex)
211 {
212 // VTK format always specifies vertex coordinates with 3 components
213 Point<3> x;
214 in >> x[0] >> x[1] >> x[2];
215
216 vertices.emplace_back();
217 for (unsigned int d = 0; d < spacedim; ++d)
218 vertices.back()[d] = x[d];
219 }
220 }
221
222 else
223 AssertThrow(false,
225 "While reading VTK file, failed to find POINTS section"));
226
227 in >> keyword;
228
229 unsigned int n_geometric_objects = 0;
230 unsigned int n_ints;
231
232 if (keyword == "CELLS")
233 {
234 // jump to the `CELL_TYPES` section and read in cell types
235 std::vector<unsigned int> cell_types;
236 {
237 std::streampos oldpos = in.tellg();
238
239
240 while (in >> keyword)
241 if (keyword == "CELL_TYPES")
242 {
243 in >> n_ints;
244
245 cell_types.resize(n_ints);
246
247 for (unsigned int i = 0; i < n_ints; ++i)
248 in >> cell_types[i];
249
250 break;
251 }
252
253 in.seekg(oldpos);
254 }
255
256 in >> n_geometric_objects;
257 in >> n_ints; // Ignore this, since we don't need it.
258
259 if (dim == 3)
260 {
261 for (unsigned int count = 0; count < n_geometric_objects; ++count)
262 {
263 unsigned int n_vertices;
264 in >> n_vertices;
265
266 // VTK_TETRA is 10, VTK_HEXAHEDRON is 12
267 if (cell_types[count] == 10 || cell_types[count] == 12)
268 {
269 // we assume that the file contains first all cells,
270 // and only then any faces or lines
271 AssertThrow(subcelldata.boundary_quads.empty() &&
272 subcelldata.boundary_lines.empty(),
274
275 cells.emplace_back(n_vertices);
276
277 for (unsigned int j = 0; j < n_vertices;
278 j++) // loop to feed data
279 in >> cells.back().vertices[j];
280
281 // Hexahedra need a permutation to go from VTK numbering
282 // to deal numbering
283 if (cell_types[count] == 12)
284 {
285 std::swap(cells.back().vertices[2],
286 cells.back().vertices[3]);
287 std::swap(cells.back().vertices[6],
288 cells.back().vertices[7]);
289 }
290
291 cells.back().material_id = 0;
292 }
293 // VTK_TRIANGLE is 5, VTK_QUAD is 9
294 else if (cell_types[count] == 5 || cell_types[count] == 9)
295 {
296 // we assume that the file contains first all cells,
297 // then all faces, and finally all lines
298 AssertThrow(subcelldata.boundary_lines.empty(),
300
301 subcelldata.boundary_quads.emplace_back(n_vertices);
302
303 for (unsigned int j = 0; j < n_vertices;
304 j++) // loop to feed the data to the boundary
305 in >> subcelldata.boundary_quads.back().vertices[j];
306
307 subcelldata.boundary_quads.back().material_id = 0;
308 }
309 // VTK_LINE is 3
310 else if (cell_types[count] == 3)
311 {
312 subcelldata.boundary_lines.emplace_back(n_vertices);
313
314 for (unsigned int j = 0; j < n_vertices;
315 j++) // loop to feed the data to the boundary
316 in >> subcelldata.boundary_lines.back().vertices[j];
317
318 subcelldata.boundary_lines.back().material_id = 0;
319 }
320
321 else
323 false,
325 "While reading VTK file, unknown cell type encountered"));
326 }
327 }
328 else if (dim == 2)
329 {
330 for (unsigned int count = 0; count < n_geometric_objects; ++count)
331 {
332 unsigned int n_vertices;
333 in >> n_vertices;
334
335 // VTK_TRIANGLE is 5, VTK_QUAD is 9
336 if (cell_types[count] == 5 || cell_types[count] == 9)
337 {
338 // we assume that the file contains first all cells,
339 // and only then any faces
340 AssertThrow(subcelldata.boundary_lines.empty(),
342
343 cells.emplace_back(n_vertices);
344
345 for (unsigned int j = 0; j < n_vertices;
346 j++) // loop to feed data
347 in >> cells.back().vertices[j];
348
349 // Quadrilaterals need a permutation to go from VTK numbering
350 // to deal numbering
351 if (cell_types[count] == 9)
352 {
353 // Like Hexahedra - the last two vertices need to be
354 // flipped
355 std::swap(cells.back().vertices[2],
356 cells.back().vertices[3]);
357 }
358
359 cells.back().material_id = 0;
360 }
361 // VTK_LINE is 3
362 else if (cell_types[count] == 3)
363 {
364 // If this is encountered, the pointer comes out of the loop
365 // and starts processing boundaries.
366 subcelldata.boundary_lines.emplace_back(n_vertices);
367
368 for (unsigned int j = 0; j < n_vertices;
369 j++) // loop to feed the data to the boundary
370 {
371 in >> subcelldata.boundary_lines.back().vertices[j];
372 }
373
374 subcelldata.boundary_lines.back().material_id = 0;
375 }
376
377 else
379 false,
381 "While reading VTK file, unknown cell type encountered"));
382 }
383 }
384 else if (dim == 1)
385 {
386 for (unsigned int count = 0; count < n_geometric_objects; ++count)
387 {
388 unsigned int type;
389 in >> type;
390
392 cell_types[count] == 3 && type == 2,
394 "While reading VTK file, unknown cell type encountered"));
395 cells.emplace_back(type);
396
397 for (unsigned int j = 0; j < type; ++j) // loop to feed data
398 in >> cells.back().vertices[j];
399
400 cells.back().material_id = 0;
401 }
402 }
403 else
404 AssertThrow(false,
406 "While reading VTK file, failed to find CELLS section"));
407
408 // Processing the CELL_TYPES section
409
410 in >> keyword;
411
413 keyword == "CELL_TYPES",
414 ExcMessage(std::string(
415 "While reading VTK file, missing CELL_TYPES section. Found <" +
416 keyword + "> instead.")));
417
418 in >> n_ints;
420 n_ints == n_geometric_objects,
421 ExcMessage("The VTK reader found a CELL_DATA statement "
422 "that lists a total of " +
424 " cell data objects, but this needs to "
425 "equal the number of cells (which is " +
426 Utilities::int_to_string(cells.size()) +
427 ") plus the number of quads (" +
428 Utilities::int_to_string(subcelldata.boundary_quads.size()) +
429 " in 3d or the number of lines (" +
430 Utilities::int_to_string(subcelldata.boundary_lines.size()) +
431 ") in 2d."));
432
433 int tmp_int;
434 for (unsigned int i = 0; i < n_ints; ++i)
435 in >> tmp_int;
436
437
438 // Processing the CELL_DATA and FIELD_DATA sections
439
440 // Ignore everything up to CELL_DATA
441 while (in >> keyword)
442 {
443 if (keyword == "CELL_DATA")
444 {
445 unsigned int n_ids;
446 in >> n_ids;
447
449 n_ids == n_geometric_objects,
451 "The VTK reader found a CELL_DATA statement "
452 "that lists a total of " +
454 " cell data objects, but this needs to "
455 "equal the number of cells (which is " +
456 Utilities::int_to_string(cells.size()) +
457 ") plus the number of quads (" +
458 Utilities::int_to_string(subcelldata.boundary_quads.size()) +
459 " in 3d or the number of lines (" +
460 Utilities::int_to_string(subcelldata.boundary_lines.size()) +
461 ") in 2d."));
462
463 const std::vector<std::string> data_sets{"MaterialID",
464 "ManifoldID"};
465
466 in >> keyword;
467 for (unsigned int i = 0; i < data_sets.size(); ++i)
468 {
469 // Ignore everything until we get to a SCALARS data set
470 if (keyword == "SCALARS")
471 {
472 // Now see if we know about this type of data set,
473 // if not, just ignore everything till the next SCALARS
474 // keyword
475 std::string field_name;
476 in >> field_name;
477 if (std::find(data_sets.begin(),
478 data_sets.end(),
479 field_name) == data_sets.end())
480 // The data set here is not one of the ones we know, so
481 // keep ignoring everything until the next SCALARS
482 // keyword.
483 continue;
484
485 // Now we got somewhere. Proceed from here, assert
486 // that the type of the table is int, and ignore the
487 // rest of the line.
488 // SCALARS MaterialID int 1
489 // (the last number is optional)
490 std::string line;
491 std::getline(in, line);
493 line.substr(1,
494 std::min(static_cast<std::size_t>(3),
495 line.size() - 1)) == "int",
497 "While reading VTK file, material- and manifold IDs can only have type 'int'."));
498
499 in >> keyword;
501 keyword == "LOOKUP_TABLE",
503 "While reading VTK file, missing keyword 'LOOKUP_TABLE'."));
504
505 in >> keyword;
507 keyword == "default",
509 "While reading VTK file, missing keyword 'default'."));
510
511 // read material or manifold ids first for all cells,
512 // then for all faces, and finally for all lines. the
513 // assumption that cells come before all faces and
514 // lines has been verified above via an assertion, so
515 // the order used in the following blocks makes sense
516 for (unsigned int i = 0; i < cells.size(); ++i)
517 {
518 int id;
519 in >> id;
520 if (field_name == "MaterialID")
521 cells[i].material_id =
522 static_cast<types::material_id>(id);
523 else if (field_name == "ManifoldID")
524 cells[i].manifold_id =
525 static_cast<types::manifold_id>(id);
526 else
528 }
529
530 if (dim == 3)
531 {
532 for (auto &boundary_quad : subcelldata.boundary_quads)
533 {
534 int id;
535 in >> id;
536 if (field_name == "MaterialID")
537 boundary_quad.material_id =
538 static_cast<types::material_id>(id);
539 else if (field_name == "ManifoldID")
540 boundary_quad.manifold_id =
541 static_cast<types::manifold_id>(id);
542 else
544 }
545 for (auto &boundary_line : subcelldata.boundary_lines)
546 {
547 int id;
548 in >> id;
549 if (field_name == "MaterialID")
550 boundary_line.material_id =
551 static_cast<types::material_id>(id);
552 else if (field_name == "ManifoldID")
553 boundary_line.manifold_id =
554 static_cast<types::manifold_id>(id);
555 else
557 }
558 }
559 else if (dim == 2)
560 {
561 for (auto &boundary_line : subcelldata.boundary_lines)
562 {
563 int id;
564 in >> id;
565 if (field_name == "MaterialID")
566 boundary_line.material_id =
567 static_cast<types::material_id>(id);
568 else if (field_name == "ManifoldID")
569 boundary_line.manifold_id =
570 static_cast<types::manifold_id>(id);
571 else
573 }
574 }
575 }
576 // check if a second SCALAR exists. If so, read the new
577 // keyword SCALARS, otherwise, return to the bookmarked
578 // position.
579 std::streampos oldpos = in.tellg();
580 in >> keyword;
581 if (keyword == "SCALARS")
582 continue;
583 else
584 in.seekg(oldpos);
585 }
586 }
587
588
589 // Addition of FIELD DATA:
590
591
592 else if (keyword == "FIELD")
593 {
594 unsigned int n_fields;
595 in >> keyword;
597 keyword == "FieldData",
599 "While reading VTK file, missing keyword FieldData"));
600
601 in >> n_fields;
602
603 for (unsigned int i = 0; i < n_fields; ++i)
604 {
605 std::string section_name;
606 std::string data_type;
607 unsigned int temp, n_ids;
608 double data;
609 in >> section_name;
610 in >> temp;
611 in >> n_ids;
613 n_ids == n_geometric_objects,
615 "The VTK reader found a FIELD statement "
616 "that lists a total of " +
618 " cell data objects, but this needs to equal the number of cells (which is " +
619 Utilities::int_to_string(cells.size()) +
620 ") plus the number of quads (" +
622 subcelldata.boundary_quads.size()) +
623 " in 3d or the number of lines (" +
625 subcelldata.boundary_lines.size()) +
626 ") in 2d."));
627 in >> data_type;
628 Vector<double> temp_data;
629 temp_data.reinit(n_ids);
630 for (unsigned int j = 0; j < n_ids; ++j)
631 {
632 in >> data;
633 if (j < cells.size())
634 temp_data[j] = data;
635 }
636 this->cell_data[section_name] = std::move(temp_data);
637 }
638 }
639 else
640 {
641 // just ignore a line that doesn't start with any of the
642 // recognized tags
643 }
644 } // end of while loop
645 Assert(subcelldata.check_consistency(dim), ExcInternalError());
646
647 apply_grid_fixup_functions(vertices, cells, subcelldata);
648 tria->create_triangulation(vertices, cells, subcelldata);
649 }
650 else
651 AssertThrow(false,
653 "While reading VTK file, failed to find CELLS section"));
654}
655
656template <int dim, int spacedim>
657const std::map<std::string, Vector<double>> &
659{
660 return this->cell_data;
661}
662
663template <int dim, int spacedim>
664void
666{
667 namespace pt = boost::property_tree;
668 pt::ptree tree;
669 pt::read_xml(in, tree);
670 auto section = tree.get_optional<std::string>("VTKFile.dealiiData");
671
672 AssertThrow(section,
674 "While reading a VTU file, failed to find dealiiData section. "
675 "Notice that we can only read grid files in .vtu format that "
676 "were created by the deal.II library, using a call to "
677 "GridOut::write_vtu(), where the flag "
678 "GridOutFlags::Vtu::serialize_triangulation is set to true."));
679
680 const auto decoded =
681 Utilities::decode_base64({section->begin(), section->end() - 1});
682 const auto string_archive =
683 Utilities::decompress({decoded.begin(), decoded.end()});
684 std::istringstream in_stream(string_archive);
685 boost::archive::binary_iarchive ia(in_stream);
686 tria->load(ia, 0);
687}
688
689
690template <int dim, int spacedim>
691void
693{
694 Assert(tria != nullptr, ExcNoTriangulationSelected());
695 Assert((dim == 2) || (dim == 3), ExcNotImplemented());
696
697 AssertThrow(in.fail() == false, ExcIO());
698 skip_comment_lines(in, '#'); // skip comments (if any) at beginning of file
699
700 int tmp;
701
702 // loop over sections, read until section 2411 is found, and break once found
703 while (true)
704 {
705 AssertThrow(in.fail() == false, ExcIO());
706 in >> tmp;
707 AssertThrow(tmp == -1,
708 ExcMessage("Invalid UNV file format. "
709 "Expected '-1' before and after a section."));
710
711 AssertThrow(in.fail() == false, ExcIO());
712 in >> tmp;
713 AssertThrow(tmp >= 0, ExcUnknownSectionType(tmp));
714 if (tmp != 2411)
715 {
716 // read until the end of any section that is not 2411
717 while (true)
718 {
719 std::string line;
720 AssertThrow(in.fail() == false, ExcIO());
721 std::getline(in, line);
722 // remove leading and trailing spaces in the line
723 boost::algorithm::trim(line);
724 if (line.compare("-1") == 0) // end of section
725 break;
726 }
727 }
728 else
729 break; // found section 2411
730 }
731
732 // section 2411 describes vertices: see the following links
733 // https://docs.plm.automation.siemens.com/tdoc/nx/12/nx_help#uid:xid1128419:index_advanced:xid1404601:xid1404604
734 // https://www.ceas3.uc.edu/sdrluff/
735 std::vector<Point<spacedim>> vertices; // vector of vertex coordinates
736 std::map<int, int>
737 vertex_indices; // # vert in unv (key) ---> # vert in deal.II (value)
738
739 int n_vertices = 0; // deal.II
740
741 while (tmp != -1) // we do until reach end of 2411
742 {
743 int vertex_index; // unv
744 int dummy;
745 double x[3];
746
747 AssertThrow(in.fail() == false, ExcIO());
748 in >> vertex_index;
749
750 tmp = vertex_index;
751 if (tmp == -1)
752 break;
753
754 in >> dummy >> dummy >> dummy;
755
756 AssertThrow(in.fail() == false, ExcIO());
757 in >> x[0] >> x[1] >> x[2];
758
759 vertices.emplace_back();
760
761 for (unsigned int d = 0; d < spacedim; ++d)
762 vertices.back()[d] = x[d];
763
764 vertex_indices[vertex_index] = n_vertices;
765
766 ++n_vertices;
767 }
768
769 AssertThrow(in.fail() == false, ExcIO());
770 in >> tmp;
771 AssertThrow(in.fail() == false, ExcIO());
772 in >> tmp;
773
774 // section 2412 describes elements: see
775 // http://www.sdrl.uc.edu/sdrl/referenceinfo/universalfileformats/file-format-storehouse/universal-dataset-number-2412
776 AssertThrow(tmp == 2412, ExcUnknownSectionType(tmp));
777
778 std::vector<CellData<dim>> cells; // vector of cells
779 SubCellData subcelldata;
780
781 std::map<int, int>
782 cell_indices; // # cell in unv (key) ---> # cell in deal.II (value)
783 std::map<int, int>
784 line_indices; // # line in unv (key) ---> # line in deal.II (value)
785 std::map<int, int>
786 quad_indices; // # quad in unv (key) ---> # quad in deal.II (value)
787
788 int n_cells = 0; // deal.II
789 int n_lines = 0; // deal.II
790 int n_quads = 0; // deal.II
791
792 while (tmp != -1) // we do until reach end of 2412
793 {
794 int object_index; // unv
795 int type;
796 int dummy;
797
798 AssertThrow(in.fail() == false, ExcIO());
799 in >> object_index;
800
801 tmp = object_index;
802 if (tmp == -1)
803 break;
804
805 in >> type >> dummy >> dummy >> dummy >> dummy;
806
807 AssertThrow((type == 11) || (type == 44) || (type == 94) || (type == 115),
808 ExcUnknownElementType(type));
809
810 if ((((type == 44) || (type == 94)) && (dim == 2)) ||
811 ((type == 115) && (dim == 3))) // cell
812 {
813 const auto reference_cell = ReferenceCells::get_hypercube<dim>();
814 cells.emplace_back();
815
816 AssertThrow(in.fail() == false, ExcIO());
817 for (const unsigned int v : GeometryInfo<dim>::vertex_indices())
818 in >> cells.back()
819 .vertices[reference_cell.unv_vertex_to_deal_vertex(v)];
820
821 cells.back().material_id = 0;
822
823 for (const unsigned int v : GeometryInfo<dim>::vertex_indices())
824 cells.back().vertices[v] = vertex_indices[cells.back().vertices[v]];
825
826 cell_indices[object_index] = n_cells;
827
828 ++n_cells;
829 }
830 else if (((type == 11) && (dim == 2)) ||
831 ((type == 11) && (dim == 3))) // boundary line
832 {
833 AssertThrow(in.fail() == false, ExcIO());
834 in >> dummy >> dummy >> dummy;
835
836 subcelldata.boundary_lines.emplace_back();
837
838 AssertThrow(in.fail() == false, ExcIO());
839 for (unsigned int &vertex :
840 subcelldata.boundary_lines.back().vertices)
841 in >> vertex;
842
843 subcelldata.boundary_lines.back().material_id = 0;
844
845 for (unsigned int &vertex :
846 subcelldata.boundary_lines.back().vertices)
847 vertex = vertex_indices[vertex];
848
849 line_indices[object_index] = n_lines;
850
851 ++n_lines;
852 }
853 else if (((type == 44) || (type == 94)) && (dim == 3)) // boundary quad
854 {
855 const auto reference_cell = ReferenceCells::Quadrilateral;
856 subcelldata.boundary_quads.emplace_back();
857
858 AssertThrow(in.fail() == false, ExcIO());
859 Assert(subcelldata.boundary_quads.back().vertices.size() ==
862 for (const unsigned int v : GeometryInfo<2>::vertex_indices())
863 in >> subcelldata.boundary_quads.back()
864 .vertices[reference_cell.unv_vertex_to_deal_vertex(v)];
865
866 subcelldata.boundary_quads.back().material_id = 0;
867
868 for (unsigned int &vertex :
869 subcelldata.boundary_quads.back().vertices)
870 vertex = vertex_indices[vertex];
871
872 quad_indices[object_index] = n_quads;
873
874 ++n_quads;
875 }
876 else
877 AssertThrow(false,
878 ExcMessage("Unknown element label <" +
880 "> when running in dim=" +
882 }
883
884 // note that so far all materials and bcs are explicitly set to 0
885 // if we do not need more info on materials and bcs - this is end of file
886 // if we do - section 2467 or 2477 comes
887
888 in >> tmp; // tmp can be either -1 or end-of-file
889
890 if (!in.eof())
891 {
892 AssertThrow(in.fail() == false, ExcIO());
893 in >> tmp;
894
895 // section 2467 (2477) describes (materials - first and bcs - second) or
896 // (bcs - first and materials - second) - sequence depends on which
897 // group is created first: see
898 // http://www.sdrl.uc.edu/sdrl/referenceinfo/universalfileformats/file-format-storehouse/universal-dataset-number-2467
899 AssertThrow((tmp == 2467) || (tmp == 2477), ExcUnknownSectionType(tmp));
900
901 while (tmp != -1) // we do until reach end of 2467 or 2477
902 {
903 int n_entities; // number of entities in group
904 long id; // id is either material or bc
905 int no; // unv
906 int dummy;
907
908 AssertThrow(in.fail() == false, ExcIO());
909 in >> dummy;
910
911 tmp = dummy;
912 if (tmp == -1)
913 break;
914
915 in >> dummy >> dummy >> dummy >> dummy >> dummy >> dummy >>
916 n_entities;
917
918 AssertThrow(in.fail() == false, ExcIO());
919 // Occasionally we encounter IDs that are not integers - we don't
920 // support that case since there is no sane way for us to determine
921 // integer IDs from, e.g., strings.
922 std::string line;
923 // The next character in the input buffer is a newline character so
924 // we need a call to std::getline() to retrieve it (it is logically
925 // a line):
926 std::getline(in, line);
927 AssertThrow(line.empty(),
929 "The line before the line containing an ID has too "
930 "many entries. This is not a valid UNV file."));
931 // now get the line containing the id:
932 std::getline(in, line);
933 AssertThrow(in.fail() == false, ExcIO());
934 std::istringstream id_stream(line);
935 id_stream >> id;
937 !id_stream.fail() && id_stream.eof(),
939 "The given UNV file contains a boundary or material id set to '" +
940 line +
941 "', which cannot be parsed as a fixed-width integer, whereas "
942 "deal.II only supports integer boundary and material ids. To fix "
943 "this, ensure that all such ids are given integer values."));
945 0 <= id &&
946 id <= long(std::numeric_limits<types::material_id>::max()),
947 ExcMessage("The provided integer id '" + std::to_string(id) +
948 "' is not convertible to either types::material_id nor "
949 "types::boundary_id."));
950
951 const unsigned int n_lines =
952 (n_entities % 2 == 0) ? (n_entities / 2) : ((n_entities + 1) / 2);
953
954 for (unsigned int line = 0; line < n_lines; ++line)
955 {
956 unsigned int n_fragments;
957
958 if (line == n_lines - 1)
959 n_fragments = (n_entities % 2 == 0) ? (2) : (1);
960 else
961 n_fragments = 2;
962
963 for (unsigned int no_fragment = 0; no_fragment < n_fragments;
964 no_fragment++)
965 {
966 AssertThrow(in.fail() == false, ExcIO());
967 in >> dummy >> no >> dummy >> dummy;
968
969 if (cell_indices.count(no) > 0) // cell - material
970 cells[cell_indices[no]].material_id = id;
971
972 if (line_indices.count(no) > 0) // boundary line - bc
973 subcelldata.boundary_lines[line_indices[no]].boundary_id =
974 id;
975
976 if (quad_indices.count(no) > 0) // boundary quad - bc
977 subcelldata.boundary_quads[quad_indices[no]].boundary_id =
978 id;
979 }
980 }
981 }
982 }
983
984 apply_grid_fixup_functions(vertices, cells, subcelldata);
985 tria->create_triangulation(vertices, cells, subcelldata);
986}
987
988
989
990template <int dim, int spacedim>
991void
993 const bool apply_all_indicators_to_manifolds)
994{
995 Assert(tria != nullptr, ExcNoTriangulationSelected());
996 AssertThrow(in.fail() == false, ExcIO());
997
998 // skip comments at start of file
999 skip_comment_lines(in, '#');
1000
1001
1002 unsigned int n_vertices;
1003 unsigned int n_cells;
1004 int dummy;
1005
1006 in >> n_vertices >> n_cells >> dummy // number of data vectors
1007 >> dummy // cell data
1008 >> dummy; // model data
1009 AssertThrow(in.fail() == false, ExcIO());
1010
1011 // set up array of vertices
1012 std::vector<Point<spacedim>> vertices(n_vertices);
1013 // set up mapping between numbering
1014 // in ucd-file (key) and in the
1015 // vertices vector
1016 std::map<int, int> vertex_indices;
1017
1018 for (unsigned int vertex = 0; vertex < n_vertices; ++vertex)
1019 {
1020 int vertex_number;
1021 double x[3];
1022
1023 // read vertex
1024 AssertThrow(in.fail() == false, ExcIO());
1025 in >> vertex_number >> x[0] >> x[1] >> x[2];
1026
1027 // store vertex
1028 for (unsigned int d = 0; d < spacedim; ++d)
1029 vertices[vertex][d] = x[d];
1030 // store mapping; note that
1031 // vertices_indices[i] is automatically
1032 // created upon first usage
1033 vertex_indices[vertex_number] = vertex;
1034 }
1035
1036 // set up array of cells
1037 std::vector<CellData<dim>> cells;
1038 SubCellData subcelldata;
1039
1040 for (unsigned int cell = 0; cell < n_cells; ++cell)
1041 {
1042 // note that since in the input
1043 // file we found the number of
1044 // cells at the top, there
1045 // should still be input here,
1046 // so check this:
1047 AssertThrow(in.fail() == false, ExcIO());
1048
1049 std::string cell_type;
1050
1051 // we use an unsigned int because we
1052 // fill this variable through an read-in process
1053 unsigned int material_id;
1054
1055 in >> dummy // cell number
1056 >> material_id;
1057 in >> cell_type;
1058
1059 if (((cell_type == "line") && (dim == 1)) ||
1060 ((cell_type == "quad") && (dim == 2)) ||
1061 ((cell_type == "hex") && (dim == 3)))
1062 // found a cell
1063 {
1064 // allocate and read indices
1065 cells.emplace_back();
1066 for (const unsigned int i : GeometryInfo<dim>::vertex_indices())
1067 in >> cells.back().vertices[GeometryInfo<dim>::ucd_to_deal[i]];
1068
1069 // to make sure that the cast won't fail
1070 Assert(material_id <= std::numeric_limits<types::material_id>::max(),
1071 ExcIndexRange(material_id,
1072 0,
1073 std::numeric_limits<types::material_id>::max()));
1074 // we use only material_ids in the range from 0 to
1075 // numbers::invalid_material_id-1
1077
1078 if (apply_all_indicators_to_manifolds)
1079 cells.back().manifold_id =
1080 static_cast<types::manifold_id>(material_id);
1081 cells.back().material_id = material_id;
1082
1083 // transform from ucd to
1084 // consecutive numbering
1085 for (const unsigned int i : GeometryInfo<dim>::vertex_indices())
1086 if (vertex_indices.find(cells.back().vertices[i]) !=
1087 vertex_indices.end())
1088 // vertex with this index exists
1089 cells.back().vertices[i] =
1090 vertex_indices[cells.back().vertices[i]];
1091 else
1092 {
1093 // no such vertex index
1094 AssertThrow(false,
1095 ExcInvalidVertexIndex(cell,
1096 cells.back().vertices[i]));
1097
1098 cells.back().vertices[i] = numbers::invalid_unsigned_int;
1099 }
1100 }
1101 else if ((cell_type == "line") && ((dim == 2) || (dim == 3)))
1102 // boundary info
1103 {
1104 subcelldata.boundary_lines.emplace_back();
1105 in >> subcelldata.boundary_lines.back().vertices[0] >>
1106 subcelldata.boundary_lines.back().vertices[1];
1107
1108 // to make sure that the cast won't fail
1109 Assert(material_id <= std::numeric_limits<types::boundary_id>::max(),
1110 ExcIndexRange(material_id,
1111 0,
1112 std::numeric_limits<types::boundary_id>::max()));
1113 // we use only boundary_ids in the range from 0 to
1114 // numbers::internal_face_boundary_id-1
1116
1117 // Make sure to set both manifold id and boundary id appropriately in
1118 // both cases:
1119 // numbers::internal_face_boundary_id and numbers::flat_manifold_id
1120 // are ignored in Triangulation::create_triangulation.
1121 if (apply_all_indicators_to_manifolds)
1122 {
1123 subcelldata.boundary_lines.back().boundary_id =
1125 subcelldata.boundary_lines.back().manifold_id =
1126 static_cast<types::manifold_id>(material_id);
1127 }
1128 else
1129 {
1130 subcelldata.boundary_lines.back().boundary_id =
1131 static_cast<types::boundary_id>(material_id);
1132 subcelldata.boundary_lines.back().manifold_id =
1134 }
1135
1136 // transform from ucd to
1137 // consecutive numbering
1138 for (unsigned int &vertex :
1139 subcelldata.boundary_lines.back().vertices)
1140 if (vertex_indices.find(vertex) != vertex_indices.end())
1141 // vertex with this index exists
1142 vertex = vertex_indices[vertex];
1143 else
1144 {
1145 // no such vertex index
1146 AssertThrow(false, ExcInvalidVertexIndex(cell, vertex));
1148 }
1149 }
1150 else if ((cell_type == "quad") && (dim == 3))
1151 // boundary info
1152 {
1153 subcelldata.boundary_quads.emplace_back();
1154 for (const unsigned int i : GeometryInfo<2>::vertex_indices())
1155 in >> subcelldata.boundary_quads.back()
1156 .vertices[GeometryInfo<2>::ucd_to_deal[i]];
1157
1158 // to make sure that the cast won't fail
1159 Assert(material_id <= std::numeric_limits<types::boundary_id>::max(),
1160 ExcIndexRange(material_id,
1161 0,
1162 std::numeric_limits<types::boundary_id>::max()));
1163 // we use only boundary_ids in the range from 0 to
1164 // numbers::internal_face_boundary_id-1
1166
1167 // Make sure to set both manifold id and boundary id appropriately in
1168 // both cases:
1169 // numbers::internal_face_boundary_id and numbers::flat_manifold_id
1170 // are ignored in Triangulation::create_triangulation.
1171 if (apply_all_indicators_to_manifolds)
1172 {
1173 subcelldata.boundary_quads.back().boundary_id =
1175 subcelldata.boundary_quads.back().manifold_id =
1176 static_cast<types::manifold_id>(material_id);
1177 }
1178 else
1179 {
1180 subcelldata.boundary_quads.back().boundary_id =
1181 static_cast<types::boundary_id>(material_id);
1182 subcelldata.boundary_quads.back().manifold_id =
1184 }
1185
1186 // transform from ucd to
1187 // consecutive numbering
1188 for (unsigned int &vertex :
1189 subcelldata.boundary_quads.back().vertices)
1190 if (vertex_indices.find(vertex) != vertex_indices.end())
1191 // vertex with this index exists
1192 vertex = vertex_indices[vertex];
1193 else
1194 {
1195 // no such vertex index
1196 Assert(false, ExcInvalidVertexIndex(cell, vertex));
1198 }
1199 }
1200 else
1201 // cannot read this
1202 AssertThrow(false, ExcUnknownIdentifier(cell_type));
1203 }
1204
1205 AssertThrow(in.fail() == false, ExcIO());
1206
1207 apply_grid_fixup_functions(vertices, cells, subcelldata);
1208 tria->create_triangulation(vertices, cells, subcelldata);
1209}
1210
1211namespace
1212{
1213 template <int dim, int spacedim>
1214 class Abaqus_to_UCD
1215 {
1216 public:
1217 Abaqus_to_UCD();
1218
1219 void
1220 read_in_abaqus(std::istream &in);
1221 void
1222 write_out_avs_ucd(std::ostream &out) const;
1223
1224 private:
1225 const double tolerance;
1226
1227 std::vector<double>
1228 get_global_node_numbers(const int face_cell_no,
1229 const int face_cell_face_no) const;
1230
1231 // NL: Stored as [ global node-id (int), x-coord, y-coord, z-coord ]
1232 std::vector<std::vector<double>> node_list;
1233 // CL: Stored as [ material-id (int), node1, node2, node3, node4, node5,
1234 // node6, node7, node8 ]
1235 std::vector<std::vector<double>> cell_list;
1236 // FL: Stored as [ sideset-id (int), node1, node2, node3, node4 ]
1237 std::vector<std::vector<double>> face_list;
1238 // ELSET: Stored as [ (std::string) elset_name = (std::vector) of cells
1239 // numbers]
1240 std::map<std::string, std::vector<int>> elsets_list;
1241 };
1242} // namespace
1243
1244template <int dim, int spacedim>
1245void
1247 const bool apply_all_indicators_to_manifolds)
1248{
1249 Assert(tria != nullptr, ExcNoTriangulationSelected());
1250 // This implementation has only been verified for:
1251 // - 2d grids with codimension 0
1252 // - 3d grids with codimension 0
1253 // - 3d grids with codimension 1
1254 Assert((spacedim == 2 && dim == spacedim) ||
1255 (spacedim == 3 && (dim == spacedim || dim == spacedim - 1)),
1257 AssertThrow(in.fail() == false, ExcIO());
1258
1259 // Read in the Abaqus file into an intermediate object
1260 // that is to be passed along to the UCD reader
1261 Abaqus_to_UCD<dim, spacedim> abaqus_to_ucd;
1262 abaqus_to_ucd.read_in_abaqus(in);
1263
1264 std::stringstream in_ucd;
1265 abaqus_to_ucd.write_out_avs_ucd(in_ucd);
1266
1267 // This next call is wrapped in a try-catch for the following reason:
1268 // It ensures that if the Abaqus mesh is read in correctly but produces
1269 // an erroneous result then the user is alerted to the source of the problem
1270 // and doesn't think that they've somehow called the wrong function.
1271 try
1272 {
1273 read_ucd(in_ucd, apply_all_indicators_to_manifolds);
1274 }
1275 catch (std::exception &exc)
1276 {
1277 std::cerr << "Exception on processing internal UCD data: " << std::endl
1278 << exc.what() << std::endl;
1279
1281 false,
1282 ExcMessage(
1283 "Internal conversion from ABAQUS file to UCD format was unsuccessful. "
1284 "More information is provided in an error message printed above. "
1285 "Are you sure that your ABAQUS mesh file conforms with the requirements "
1286 "listed in the documentation?"));
1287 }
1288 catch (...)
1289 {
1291 false,
1292 ExcMessage(
1293 "Internal conversion from ABAQUS file to UCD format was unsuccessful. "
1294 "Are you sure that your ABAQUS mesh file conforms with the requirements "
1295 "listed in the documentation?"));
1296 }
1297}
1298
1299
1300template <int dim, int spacedim>
1301void
1303{
1304 Assert(tria != nullptr, ExcNoTriangulationSelected());
1305 Assert(dim == 2, ExcNotImplemented());
1306
1307 AssertThrow(in.fail() == false, ExcIO());
1308
1309 // skip comments at start of file
1310 skip_comment_lines(in, '#');
1311
1312 // first read in identifier string
1313 std::string line;
1314 getline(in, line);
1315
1316 AssertThrow(line == "MeshVersionFormatted 0", ExcInvalidDBMESHInput(line));
1317
1318 skip_empty_lines(in);
1319
1320 // next read dimension
1321 getline(in, line);
1322 AssertThrow(line == "Dimension", ExcInvalidDBMESHInput(line));
1323 unsigned int dimension;
1324 in >> dimension;
1325 AssertThrow(dimension == dim, ExcDBMESHWrongDimension(dimension));
1326 skip_empty_lines(in);
1327
1328 // now there are a lot of fields of
1329 // which we don't know the exact
1330 // meaning and which are far from
1331 // being properly documented in the
1332 // manual. we skip everything until
1333 // we find a comment line with the
1334 // string "# END". at some point in
1335 // the future, someone may have the
1336 // knowledge to parse and interpret
1337 // the other fields in between as
1338 // well...
1339 while (getline(in, line), line.find("# END") == std::string::npos)
1340 ;
1341 skip_empty_lines(in);
1342
1343
1344 // now read vertices
1345 getline(in, line);
1346 AssertThrow(line == "Vertices", ExcInvalidDBMESHInput(line));
1347
1348 unsigned int n_vertices;
1349 double dummy;
1350
1351 in >> n_vertices;
1352 std::vector<Point<spacedim>> vertices(n_vertices);
1353 for (unsigned int vertex = 0; vertex < n_vertices; ++vertex)
1354 {
1355 // read vertex coordinates
1356 for (unsigned int d = 0; d < dim; ++d)
1357 in >> vertices[vertex][d];
1358 // read Ref phi_i, whatever that may be
1359 in >> dummy;
1360 }
1361 AssertThrow(in, ExcInvalidDBMeshFormat());
1362
1363 skip_empty_lines(in);
1364
1365 // read edges. we ignore them at
1366 // present, so just read them and
1367 // discard the input
1368 getline(in, line);
1369 AssertThrow(line == "Edges", ExcInvalidDBMESHInput(line));
1370
1371 unsigned int n_edges;
1372 in >> n_edges;
1373 for (unsigned int edge = 0; edge < n_edges; ++edge)
1374 {
1375 // read vertex indices
1376 in >> dummy >> dummy;
1377 // read Ref phi_i, whatever that may be
1378 in >> dummy;
1379 }
1380 AssertThrow(in, ExcInvalidDBMeshFormat());
1381
1382 skip_empty_lines(in);
1383
1384
1385
1386 // read cracked edges (whatever
1387 // that may be). we ignore them at
1388 // present, so just read them and
1389 // discard the input
1390 getline(in, line);
1391 AssertThrow(line == "CrackedEdges", ExcInvalidDBMESHInput(line));
1392
1393 in >> n_edges;
1394 for (unsigned int edge = 0; edge < n_edges; ++edge)
1395 {
1396 // read vertex indices
1397 in >> dummy >> dummy;
1398 // read Ref phi_i, whatever that may be
1399 in >> dummy;
1400 }
1401 AssertThrow(in, ExcInvalidDBMeshFormat());
1402
1403 skip_empty_lines(in);
1404
1405
1406 // now read cells.
1407 // set up array of cells
1408 getline(in, line);
1409 AssertThrow(line == "Quadrilaterals", ExcInvalidDBMESHInput(line));
1410
1411 static constexpr std::array<unsigned int, 8> local_vertex_numbering = {
1412 {0, 1, 5, 4, 2, 3, 7, 6}};
1413 std::vector<CellData<dim>> cells;
1414 SubCellData subcelldata;
1415 unsigned int n_cells;
1416 in >> n_cells;
1417 for (unsigned int cell = 0; cell < n_cells; ++cell)
1418 {
1419 // read in vertex numbers. they
1420 // are 1-based, so subtract one
1421 cells.emplace_back();
1422 for (const unsigned int i : GeometryInfo<dim>::vertex_indices())
1423 {
1424 in >>
1425 cells.back().vertices[dim == 3 ? local_vertex_numbering[i] :
1427
1428 AssertThrow((cells.back().vertices[i] >= 1) &&
1429 (static_cast<unsigned int>(cells.back().vertices[i]) <=
1430 vertices.size()),
1431 ExcInvalidVertexIndex(cell, cells.back().vertices[i]));
1432
1433 --cells.back().vertices[i];
1434 }
1435
1436 // read and discard Ref phi_i
1437 in >> dummy;
1438 }
1439 AssertThrow(in, ExcInvalidDBMeshFormat());
1440
1441 skip_empty_lines(in);
1442
1443
1444 // then there are again a whole lot
1445 // of fields of which I have no
1446 // clue what they mean. skip them
1447 // all and leave the interpretation
1448 // to other implementers...
1449 while (getline(in, line), ((line.find("End") == std::string::npos) && (in)))
1450 ;
1451 // ok, so we are not at the end of
1452 // the file, that's it, mostly
1453 AssertThrow(in.fail() == false, ExcIO());
1454
1455 apply_grid_fixup_functions(vertices, cells, subcelldata);
1456 tria->create_triangulation(vertices, cells, subcelldata);
1457}
1458
1459
1460
1461template <int dim, int spacedim>
1462void
1464{
1465 Assert(tria != nullptr, ExcNoTriangulationSelected());
1466 AssertThrow(in.fail() == false, ExcIO());
1467
1468 const auto reference_cell = ReferenceCells::get_hypercube<dim>();
1469
1470 std::string line;
1471 // skip comments at start of file
1472 std::getline(in, line);
1473
1474 unsigned int n_vertices;
1475 unsigned int n_cells;
1476
1477 // read cells, throw away rest of line
1478 in >> n_cells;
1479 std::getline(in, line);
1480
1481 in >> n_vertices;
1482 std::getline(in, line);
1483
1484 // ignore following 8 lines
1485 for (unsigned int i = 0; i < 8; ++i)
1486 std::getline(in, line);
1487
1488 // set up array of cells
1489 std::vector<CellData<dim>> cells(n_cells);
1490 SubCellData subcelldata;
1491
1492 for (CellData<dim> &cell : cells)
1493 {
1494 // note that since in the input file we found the number of cells at the
1495 // top, there should still be input here, so check this:
1496 AssertThrow(in.fail() == false, ExcIO());
1497
1498 // XDA happens to use ExodusII's numbering because XDA/XDR is libMesh's
1499 // native format, and libMesh's node numberings come from ExodusII:
1500 for (unsigned int i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
1501 in >> cell.vertices[reference_cell.exodusii_vertex_to_deal_vertex(i)];
1502 }
1503
1504 // set up array of vertices
1505 std::vector<Point<spacedim>> vertices(n_vertices);
1506 for (Point<spacedim> &vertex : vertices)
1507 {
1508 for (unsigned int d = 0; d < spacedim; ++d)
1509 in >> vertex[d];
1510 for (unsigned int d = spacedim; d < 3; ++d)
1511 {
1512 // file is always in 3d
1513 double dummy;
1514 in >> dummy;
1515 }
1516 }
1517 AssertThrow(in.fail() == false, ExcIO());
1518
1519 apply_grid_fixup_functions(vertices, cells, subcelldata);
1520 tria->create_triangulation(vertices, cells, subcelldata);
1521}
1522
1523
1524
1525template <int dim, int spacedim>
1526void
1528{
1529 Assert(tria != nullptr, ExcNoTriangulationSelected());
1530 AssertThrow(in.fail() == false, ExcIO());
1531
1532 // Start by making our life a bit easier: The file format
1533 // allows for comments in a whole bunch of places, including
1534 // on separate lines, at line ends, and that's just a hassle to
1535 // parse because we will have to check in every line whether there
1536 // is a comment. To make things easier, just read it all in up
1537 // front, strip comments, eat trailing whitespace, and
1538 // concatenate it all into one big string from which we will
1539 // then read. We lose the ability to output error messages tied
1540 // to individual lines of the input, but none of the other
1541 // readers does that either.
1542 std::stringstream whole_file;
1543 while (in)
1544 {
1545 // read one line
1546 std::string line;
1547 std::getline(in, line);
1548
1549 // We tend to get these sorts of files from folks who run on
1550 // Windows and where line endings are \r\n instead of just
1551 // \n. The \r is redundant unless you still use a line printer,
1552 // so get rid of it in order to not confuse any of the functions
1553 // below that try to interpret the entire content of a line
1554 // as a string:
1555 if ((line.size() > 0) && (line.back() == '\r'))
1556 line.erase(line.size() - 1);
1557
1558 // Strip trailing comments, then strip whatever spaces are at the end
1559 // of the line, and if anything is left, concatenate that to the previous
1560 // content of the file :
1561 if (line.find('#') != std::string::npos)
1562 line.erase(line.find('#'), std::string::npos);
1563 while ((line.size() > 0) && (line.back() == ' '))
1564 line.erase(line.size() - 1);
1565
1566 if (line.size() > 0)
1567 whole_file << '\n' << line;
1568 }
1569
1570 // Now start to read the contents of this so-simplified file. A typical
1571 // header of these files will look like this:
1572 // # Created by COMSOL Multiphysics.
1573 //
1574 // # Major & minor version
1575 // 0 1
1576 // 1 # number of tags
1577 // # Tags
1578 // 5 mesh1
1579 // 1 # number of types
1580 // # Types
1581 // 3 obj
1582
1583 AssertThrow(whole_file.fail() == false, ExcIO());
1584
1585 {
1586 unsigned int version_major, version_minor;
1587 whole_file >> version_major >> version_minor;
1588 AssertThrow((version_major == 0) && (version_minor == 1),
1589 ExcMessage("deal.II can currently only read version 0.1 "
1590 "of the mphtxt file format."));
1591 }
1592
1593 // It's not clear what the 'tags' are, but read them and discard them
1594 {
1595 unsigned int n_tags;
1596 whole_file >> n_tags;
1597 for (unsigned int i = 0; i < n_tags; ++i)
1598 {
1599 std::string dummy;
1600 while (whole_file.peek() == '\n')
1601 whole_file.get();
1602 std::getline(whole_file, dummy);
1603 }
1604 }
1605
1606 // Do the same with the 'types'
1607 {
1608 unsigned int n_types;
1609 whole_file >> n_types;
1610 for (unsigned int i = 0; i < n_types; ++i)
1611 {
1612 std::string dummy;
1613 while (whole_file.peek() == '\n')
1614 whole_file.get();
1615 std::getline(whole_file, dummy);
1616 }
1617 }
1618
1619 // Then move on to the actual mesh. A typical header of this part will
1620 // look like this:
1621 // # --------- Object 0 ----------
1622 //
1623 // 0 0 1
1624 // 4 Mesh # class
1625 // 4 # version
1626 // 3 # sdim
1627 // 1204 # number of mesh vertices
1628 // 0 # lowest mesh vertex index
1629 //
1630 // # Mesh vertex coordinates
1631 // ...
1632 AssertThrow(whole_file.fail() == false, ExcIO());
1633 {
1634 unsigned int dummy;
1635 whole_file >> dummy >> dummy >> dummy;
1636 }
1637 {
1638 std::string s;
1639 while (whole_file.peek() == '\n')
1640 whole_file.get();
1641 std::getline(whole_file, s);
1642 AssertThrow(s == "4 Mesh",
1643 ExcMessage("Expected '4 Mesh', but got '" + s + "'."));
1644 }
1645 {
1646 unsigned int version;
1647 whole_file >> version;
1648 AssertThrow(version == 4, ExcNotImplemented());
1649 }
1650 {
1651 unsigned int file_space_dim;
1652 whole_file >> file_space_dim;
1653
1654 AssertThrow(file_space_dim == spacedim,
1655 ExcMessage(
1656 "The mesh file uses a different number of space dimensions "
1657 "than the triangulation you want to read it into."));
1658 }
1659 unsigned int n_vertices;
1660 whole_file >> n_vertices;
1661
1662 unsigned int starting_vertex_index;
1663 whole_file >> starting_vertex_index;
1664
1665 std::vector<Point<spacedim>> vertices(n_vertices);
1666 for (unsigned int v = 0; v < n_vertices; ++v)
1667 whole_file >> vertices[v];
1668
1669 // Then comes a block that looks like this:
1670 // 4 # number of element types
1671 //
1672 // # Type #0
1673 // 3 vtx # type name
1674 //
1675 //
1676 // 1 # number of vertices per element
1677 // 18 # number of elements
1678 // # Elements
1679 // 4
1680 // 12
1681 // 19
1682 // 80
1683 // 143
1684 // [...]
1685 // 1203
1686 //
1687 // 18 # number of geometric entity indices
1688 // # Geometric entity indices
1689 // 2
1690 // 0
1691 // 11
1692 // 6
1693 // 3
1694 // [...]
1695 AssertThrow(whole_file.fail() == false, ExcIO());
1696
1697 std::vector<CellData<dim>> cells;
1698 SubCellData subcelldata;
1699
1700 unsigned int n_types;
1701 whole_file >> n_types;
1702 for (unsigned int type = 0; type < n_types; ++type)
1703 {
1704 // The object type is prefixed by the number of characters the
1705 // object type string takes up (e.g., 3 for 'tri' and 5 for
1706 // 'prism'), but we really don't need that.
1707 {
1708 unsigned int dummy;
1709 whole_file >> dummy;
1710 }
1711
1712 // Read the object type. Also do a number of safety checks.
1713 std::string object_name;
1714 whole_file >> object_name;
1715
1716 static const std::map<std::string, ReferenceCell> name_to_type = {
1717 {"vtx", ReferenceCells::Vertex},
1718 {"edg", ReferenceCells::Line},
1719 {"tri", ReferenceCells::Triangle},
1722 {"prism", ReferenceCells::Wedge}
1723 // TODO: Add hexahedra and pyramids once we have a sample input file
1724 // that contains these
1725 };
1726 AssertThrow(name_to_type.find(object_name) != name_to_type.end(),
1727 ExcMessage("The input file contains a cell type <" +
1728 object_name +
1729 "> that the reader does not "
1730 "current support"));
1731 const ReferenceCell object_type = name_to_type.at(object_name);
1732
1733 unsigned int n_vertices_per_element;
1734 whole_file >> n_vertices_per_element;
1735
1736 unsigned int n_elements;
1737 whole_file >> n_elements;
1738
1739
1740 if (object_type == ReferenceCells::Vertex)
1741 {
1742 AssertThrow(n_vertices_per_element == 1, ExcInternalError());
1743 }
1744 else if (object_type == ReferenceCells::Line)
1745 {
1746 AssertThrow(n_vertices_per_element == 2, ExcInternalError());
1747 }
1748 else if (object_type == ReferenceCells::Triangle)
1749 {
1750 AssertThrow(dim >= 2,
1751 ExcMessage("Triangles should not appear in input files "
1752 "for 1d meshes."));
1753 AssertThrow(n_vertices_per_element == 3, ExcInternalError());
1754 }
1755 else if (object_type == ReferenceCells::Quadrilateral)
1756 {
1757 AssertThrow(dim >= 2,
1758 ExcMessage(
1759 "Quadrilaterals should not appear in input files "
1760 "for 1d meshes."));
1761 AssertThrow(n_vertices_per_element == 4, ExcInternalError());
1762 }
1763 else if (object_type == ReferenceCells::Tetrahedron)
1764 {
1765 AssertThrow(dim >= 3,
1766 ExcMessage("Tetrahedra should not appear in input files "
1767 "for 1d or 2d meshes."));
1768 AssertThrow(n_vertices_per_element == 4, ExcInternalError());
1769 }
1770 else if (object_type == ReferenceCells::Wedge)
1771 {
1772 AssertThrow(dim >= 3,
1773 ExcMessage(
1774 "Prisms (wedges) should not appear in input files "
1775 "for 1d or 2d meshes."));
1776 AssertThrow(n_vertices_per_element == 6, ExcInternalError());
1777 }
1778 else
1780
1781 // Next, for each element read the vertex numbers. Then we have
1782 // to decide what to do with it. If it is a vertex, we ignore
1783 // the information. If it is a cell, we have to put it into the
1784 // appropriate object, and the same if it is an edge or
1785 // face. Since multiple object type blocks can refer to cells or
1786 // faces (e.g., for mixed meshes, or for prisms where there are
1787 // boundary triangles and boundary quads), the element index 'e'
1788 // below does not correspond to the index in the 'cells' or
1789 // 'subcelldata.boundary_*' objects; we just keep pushing
1790 // elements onto the back.
1791 //
1792 // In any case, we adjust vertex indices right after reading them based on
1793 // the starting index read above
1794 std::vector<unsigned int> vertices_for_this_element(
1795 n_vertices_per_element);
1796 for (unsigned int e = 0; e < n_elements; ++e)
1797 {
1798 AssertThrow(whole_file.fail() == false, ExcIO());
1799 for (unsigned int v = 0; v < n_vertices_per_element; ++v)
1800 {
1801 whole_file >> vertices_for_this_element[v];
1802 vertices_for_this_element[v] -= starting_vertex_index;
1803 }
1804
1805 if (object_type == ReferenceCells::Vertex)
1806 ; // do nothing
1807 else if (object_type == ReferenceCells::Line)
1808 {
1809 if (dim == 1)
1810 {
1811 cells.emplace_back();
1812 cells.back().vertices = vertices_for_this_element;
1813 }
1814 else
1815 {
1816 subcelldata.boundary_lines.emplace_back();
1817 subcelldata.boundary_lines.back().vertices =
1818 vertices_for_this_element;
1819 }
1820 }
1821 else if ((object_type == ReferenceCells::Triangle) ||
1822 (object_type == ReferenceCells::Quadrilateral))
1823 {
1824 if (dim == 2)
1825 {
1826 cells.emplace_back();
1827 cells.back().vertices = vertices_for_this_element;
1828 }
1829 else
1830 {
1831 subcelldata.boundary_quads.emplace_back();
1832 subcelldata.boundary_quads.back().vertices =
1833 vertices_for_this_element;
1834 }
1835 }
1836 else if ((object_type == ReferenceCells::Tetrahedron) ||
1837 (object_type == ReferenceCells::Wedge))
1838 {
1839 if (dim == 3)
1840 {
1841 cells.emplace_back();
1842 cells.back().vertices = vertices_for_this_element;
1843 }
1844 else
1846 }
1847 else
1849 }
1850
1851 // Then also read the "geometric entity indices". There need to
1852 // be as many as there were elements to begin with, or
1853 // alternatively zero if no geometric entity indices will be set
1854 // at all.
1855 unsigned int n_geom_entity_indices;
1856 whole_file >> n_geom_entity_indices;
1857 AssertThrow((n_geom_entity_indices == 0) ||
1858 (n_geom_entity_indices == n_elements),
1860
1861 // Loop over these objects. Since we pushed them onto the back
1862 // of various arrays before, we need to recalculate which index
1863 // in these array element 'e' corresponds to when setting
1864 // boundary and manifold indicators.
1865 if (n_geom_entity_indices != 0)
1866 {
1867 for (unsigned int e = 0; e < n_geom_entity_indices; ++e)
1868 {
1869 AssertThrow(whole_file.fail() == false, ExcIO());
1870 unsigned int geometric_entity_index;
1871 whole_file >> geometric_entity_index;
1872 if (object_type == ReferenceCells::Vertex)
1873 ; // do nothing
1874 else if (object_type == ReferenceCells::Line)
1875 {
1876 if (dim == 1)
1877 cells[cells.size() - n_elements + e].material_id =
1878 geometric_entity_index;
1879 else
1880 subcelldata
1881 .boundary_lines[subcelldata.boundary_lines.size() -
1882 n_elements + e]
1883 .boundary_id = geometric_entity_index;
1884 }
1885 else if ((object_type == ReferenceCells::Triangle) ||
1886 (object_type == ReferenceCells::Quadrilateral))
1887 {
1888 if (dim == 2)
1889 cells[cells.size() - n_elements + e].material_id =
1890 geometric_entity_index;
1891 else
1892 subcelldata
1893 .boundary_quads[subcelldata.boundary_quads.size() -
1894 n_elements + e]
1895 .boundary_id = geometric_entity_index;
1896 }
1897 else if ((object_type == ReferenceCells::Tetrahedron) ||
1898 (object_type == ReferenceCells::Wedge))
1899 {
1900 if (dim == 3)
1901 cells[cells.size() - n_elements + e].material_id =
1902 geometric_entity_index;
1903 else
1905 }
1906 else
1908 }
1909 }
1910 }
1911 AssertThrow(whole_file.fail() == false, ExcIO());
1912
1913 // Now finally create the mesh. Because of the quirk with boundary
1914 // edges and faces described in the documentation of this function,
1915 // we can't pass 'subcelldata' as third argument to this function.
1916 // Rather, we then have to fix up the generated triangulation
1917 // after the fact :-(
1918 tria->create_triangulation(vertices, cells, {});
1919
1920 // Now for the "fixing up" step mentioned above. To make things a bit
1921 // simpler, let us sort first normalize the order of vertices in edges
1922 // and triangles/quads, and then sort lexicographically:
1923 if (dim >= 2)
1924 {
1925 for (auto &line : subcelldata.boundary_lines)
1926 {
1927 Assert(line.vertices.size() == 2, ExcInternalError());
1928 if (line.vertices[1] < line.vertices[0])
1929 std::swap(line.vertices[0], line.vertices[1]);
1930 }
1931 std::sort(subcelldata.boundary_lines.begin(),
1932 subcelldata.boundary_lines.end(),
1933 [](const CellData<1> &a, const CellData<1> &b) {
1934 return std::lexicographical_compare(a.vertices.begin(),
1935 a.vertices.end(),
1936 b.vertices.begin(),
1937 b.vertices.end());
1938 });
1939 }
1940
1941 // Now for boundary faces. For triangles, we can sort the vertices in
1942 // ascending vertex index order because every order corresponds to a circular
1943 // order either seen from one side or the other. For quads, the situation is
1944 // more difficult. But fortunately, we do not actually need to keep the
1945 // vertices in any specific order because there can be no two quads with the
1946 // same vertices but listed in different orders that actually correspond to
1947 // different things. If we had given this information to
1948 // Triangulation::create_triangulation(), we would probably have wanted to
1949 // keep things in a specific order so that the vertices define a proper
1950 // coordinate system on the quad, but that's not our goal here so we just
1951 // sort.
1952 if (dim >= 3)
1953 {
1954 for (auto &face : subcelldata.boundary_quads)
1955 {
1956 Assert((face.vertices.size() == 3) || (face.vertices.size() == 4),
1958 std::sort(face.vertices.begin(), face.vertices.end());
1959 }
1960 std::sort(subcelldata.boundary_quads.begin(),
1961 subcelldata.boundary_quads.end(),
1962 [](const CellData<2> &a, const CellData<2> &b) {
1963 return std::lexicographical_compare(a.vertices.begin(),
1964 a.vertices.end(),
1965 b.vertices.begin(),
1966 b.vertices.end());
1967 });
1968 }
1969
1970 // OK, now we can finally go about fixing up edges and faces.
1971 if (dim >= 2)
1972 {
1973 for (const auto &cell : tria->active_cell_iterators())
1974 for (const auto &face : cell->face_iterators())
1975 if (face->at_boundary())
1976 {
1977 // We found a face at the boundary. Let us look up whether it
1978 // was listed in subcelldata
1979 if (dim == 2)
1980 {
1981 std::array<unsigned int, 2> face_vertex_indices = {
1982 {face->vertex_index(0), face->vertex_index(1)}};
1983 if (face_vertex_indices[0] > face_vertex_indices[1])
1984 std::swap(face_vertex_indices[0], face_vertex_indices[1]);
1985
1986 // See if we can find an edge with these indices:
1987 const auto p =
1988 std::lower_bound(subcelldata.boundary_lines.begin(),
1989 subcelldata.boundary_lines.end(),
1990 face_vertex_indices,
1991 [](const CellData<1> &a,
1992 const std::array<unsigned int, 2>
1993 &face_vertex_indices) -> bool {
1994 return std::lexicographical_compare(
1995 a.vertices.begin(),
1996 a.vertices.end(),
1997 face_vertex_indices.begin(),
1998 face_vertex_indices.end());
1999 });
2000
2001 if ((p != subcelldata.boundary_lines.end()) &&
2002 (p->vertices[0] == face_vertex_indices[0]) &&
2003 (p->vertices[1] == face_vertex_indices[1]))
2004 {
2005 face->set_boundary_id(p->boundary_id);
2006 }
2007 }
2008 else if (dim == 3)
2009 {
2010 // In 3d, we need to look things up in the boundary_quads
2011 // structure (which also stores boundary triangles) as well as
2012 // for the edges
2013 std::vector<unsigned int> face_vertex_indices(
2014 face->n_vertices());
2015 for (unsigned int v = 0; v < face->n_vertices(); ++v)
2016 face_vertex_indices[v] = face->vertex_index(v);
2017 std::sort(face_vertex_indices.begin(),
2018 face_vertex_indices.end());
2019
2020 // See if we can find a face with these indices:
2021 const auto p =
2022 std::lower_bound(subcelldata.boundary_quads.begin(),
2023 subcelldata.boundary_quads.end(),
2024 face_vertex_indices,
2025 [](const CellData<2> &a,
2026 const std::vector<unsigned int>
2027 &face_vertex_indices) -> bool {
2028 return std::lexicographical_compare(
2029 a.vertices.begin(),
2030 a.vertices.end(),
2031 face_vertex_indices.begin(),
2032 face_vertex_indices.end());
2033 });
2034
2035 if ((p != subcelldata.boundary_quads.end()) &&
2036 (p->vertices == face_vertex_indices))
2037 {
2038 face->set_boundary_id(p->boundary_id);
2039 }
2040
2041
2042 // Now do the same for the edges
2043 for (unsigned int e = 0; e < face->n_lines(); ++e)
2044 {
2045 const auto edge = face->line(e);
2046
2047 std::array<unsigned int, 2> edge_vertex_indices = {
2048 {edge->vertex_index(0), edge->vertex_index(1)}};
2049 if (edge_vertex_indices[0] > edge_vertex_indices[1])
2050 std::swap(edge_vertex_indices[0],
2051 edge_vertex_indices[1]);
2052
2053 // See if we can find an edge with these indices:
2054 const auto p =
2055 std::lower_bound(subcelldata.boundary_lines.begin(),
2056 subcelldata.boundary_lines.end(),
2057 edge_vertex_indices,
2058 [](const CellData<1> &a,
2059 const std::array<unsigned int, 2>
2060 &edge_vertex_indices) -> bool {
2061 return std::lexicographical_compare(
2062 a.vertices.begin(),
2063 a.vertices.end(),
2064 edge_vertex_indices.begin(),
2065 edge_vertex_indices.end());
2066 });
2067
2068 if ((p != subcelldata.boundary_lines.end()) &&
2069 (p->vertices[0] == edge_vertex_indices[0]) &&
2070 (p->vertices[1] == edge_vertex_indices[1]))
2071 {
2072 edge->set_boundary_id(p->boundary_id);
2073 }
2074 }
2075 }
2076 }
2077 }
2078}
2079
2080
2081template <int dim, int spacedim>
2082void
2083GridIn<dim, spacedim>::read_msh(std::istream &input_stream)
2084{
2085 Assert(tria != nullptr, ExcNoTriangulationSelected());
2086 AssertThrow(input_stream.fail() == false, ExcIO());
2087
2088 unsigned int n_vertices;
2089 unsigned int n_cells;
2090 unsigned int dummy;
2091 std::string line;
2092 // This array stores maps from the 'entities' to the 'physical tags' for
2093 // points, curves, surfaces and volumes. We use this information later to
2094 // assign boundary ids.
2095 std::array<std::map<int, int>, 4> tag_maps;
2096
2097 // contain the content of the file stripped of the comments
2098 std::string stripped_file;
2099
2100 // Comments can be included by mesh generating software and must be deleted,
2101 // a string is filed with the content of the file stripped of the comments
2102 while (std::getline(input_stream, line))
2103 {
2104 if (line == "@f$Comments")
2105 {
2106 while (std::getline(input_stream, line))
2107 {
2108 if (line == "@f$EndComments")
2109 {
2110 break;
2111 }
2112 }
2113 continue;
2114 }
2115 stripped_file += line + '\n';
2116 }
2117
2118 // Restart reading the file normally since it has been stripped of comments
2119 std::istringstream in(stripped_file);
2120
2121 in >> line;
2122
2123 // first determine file format
2124 unsigned int gmsh_file_format = 0;
2125 if (line == "@f$NOD")
2126 gmsh_file_format = 10;
2127 else if (line == "@f$MeshFormat")
2128 gmsh_file_format = 20;
2129 else
2130 AssertThrow(false, ExcInvalidGMSHInput(line));
2131
2132 // if file format is 2.0 or greater then we also have to read the rest of
2133 // the header
2134 if (gmsh_file_format == 20)
2135 {
2136 double version;
2137 unsigned int file_type, data_size;
2138
2139 in >> version >> file_type >> data_size;
2140
2141 Assert((version >= 2.0) && (version <= 4.1), ExcNotImplemented());
2142 gmsh_file_format = static_cast<unsigned int>(version * 10);
2143
2144 Assert(file_type == 0, ExcNotImplemented());
2145 Assert(data_size == sizeof(double), ExcNotImplemented());
2146
2147 // read the end of the header and the first line of the nodes
2148 // description to synch ourselves with the format 1 handling above
2149 in >> line;
2150 AssertThrow(line == "@f$EndMeshFormat", ExcInvalidGMSHInput(line));
2151
2152 in >> line;
2153 // if the next block is of kind @f$PhysicalNames, ignore it
2154 if (line == "@f$PhysicalNames")
2155 {
2156 do
2157 {
2158 in >> line;
2159 }
2160 while (line != "@f$EndPhysicalNames");
2161 in >> line;
2162 }
2163
2164 // if the next block is of kind @f$Entities, parse it
2165 if (line == "@f$Entities")
2166 {
2167 unsigned long n_points, n_curves, n_surfaces, n_volumes;
2168
2169 in >> n_points >> n_curves >> n_surfaces >> n_volumes;
2170 for (unsigned int i = 0; i < n_points; ++i)
2171 {
2172 // parse point ids
2173 int tag;
2174 unsigned int n_physicals;
2175 double box_min_x, box_min_y, box_min_z, box_max_x, box_max_y,
2176 box_max_z;
2177
2178 // we only care for 'tag' as key for tag_maps[0]
2179 if (gmsh_file_format > 40)
2180 {
2181 in >> tag >> box_min_x >> box_min_y >> box_min_z >>
2182 n_physicals;
2183 box_max_x = box_min_x;
2184 box_max_y = box_min_y;
2185 box_max_z = box_min_z;
2186 }
2187 else
2188 {
2189 in >> tag >> box_min_x >> box_min_y >> box_min_z >>
2190 box_max_x >> box_max_y >> box_max_z >> n_physicals;
2191 }
2192 // if there is a physical tag, we will use it as boundary id
2193 // below
2194 AssertThrow(n_physicals < 2,
2195 ExcMessage("More than one tag is not supported!"));
2196 // if there is no physical tag, use 0 as default
2197 int physical_tag = 0;
2198 for (unsigned int j = 0; j < n_physicals; ++j)
2199 in >> physical_tag;
2200 tag_maps[0][tag] = physical_tag;
2201 }
2202 for (unsigned int i = 0; i < n_curves; ++i)
2203 {
2204 // parse curve ids
2205 int tag;
2206 unsigned int n_physicals;
2207 double box_min_x, box_min_y, box_min_z, box_max_x, box_max_y,
2208 box_max_z;
2209
2210 // we only care for 'tag' as key for tag_maps[1]
2211 in >> tag >> box_min_x >> box_min_y >> box_min_z >> box_max_x >>
2212 box_max_y >> box_max_z >> n_physicals;
2213 // if there is a physical tag, we will use it as boundary id
2214 // below
2215 AssertThrow(n_physicals < 2,
2216 ExcMessage("More than one tag is not supported!"));
2217 // if there is no physical tag, use 0 as default
2218 int physical_tag = 0;
2219 for (unsigned int j = 0; j < n_physicals; ++j)
2220 in >> physical_tag;
2221 tag_maps[1][tag] = physical_tag;
2222 // we don't care about the points associated to a curve, but
2223 // have to parse them anyway because their format is
2224 // unstructured
2225 in >> n_points;
2226 for (unsigned int j = 0; j < n_points; ++j)
2227 in >> tag;
2228 }
2229
2230 for (unsigned int i = 0; i < n_surfaces; ++i)
2231 {
2232 // parse surface ids
2233 int tag;
2234 unsigned int n_physicals;
2235 double box_min_x, box_min_y, box_min_z, box_max_x, box_max_y,
2236 box_max_z;
2237
2238 // we only care for 'tag' as key for tag_maps[2]
2239 in >> tag >> box_min_x >> box_min_y >> box_min_z >> box_max_x >>
2240 box_max_y >> box_max_z >> n_physicals;
2241 // if there is a physical tag, we will use it as boundary id
2242 // below
2243 AssertThrow(n_physicals < 2,
2244 ExcMessage("More than one tag is not supported!"));
2245 // if there is no physical tag, use 0 as default
2246 int physical_tag = 0;
2247 for (unsigned int j = 0; j < n_physicals; ++j)
2248 in >> physical_tag;
2249 tag_maps[2][tag] = physical_tag;
2250 // we don't care about the curves associated to a surface, but
2251 // have to parse them anyway because their format is
2252 // unstructured
2253 in >> n_curves;
2254 for (unsigned int j = 0; j < n_curves; ++j)
2255 in >> tag;
2256 }
2257 for (unsigned int i = 0; i < n_volumes; ++i)
2258 {
2259 // parse volume ids
2260 int tag;
2261 unsigned int n_physicals;
2262 double box_min_x, box_min_y, box_min_z, box_max_x, box_max_y,
2263 box_max_z;
2264
2265 // we only care for 'tag' as key for tag_maps[3]
2266 in >> tag >> box_min_x >> box_min_y >> box_min_z >> box_max_x >>
2267 box_max_y >> box_max_z >> n_physicals;
2268 // if there is a physical tag, we will use it as boundary id
2269 // below
2270 AssertThrow(n_physicals < 2,
2271 ExcMessage("More than one tag is not supported!"));
2272 // if there is no physical tag, use 0 as default
2273 int physical_tag = 0;
2274 for (unsigned int j = 0; j < n_physicals; ++j)
2275 in >> physical_tag;
2276 tag_maps[3][tag] = physical_tag;
2277 // we don't care about the surfaces associated to a volume, but
2278 // have to parse them anyway because their format is
2279 // unstructured
2280 in >> n_surfaces;
2281 for (unsigned int j = 0; j < n_surfaces; ++j)
2282 in >> tag;
2283 }
2284 in >> line;
2285 AssertThrow(line == "@f$EndEntities", ExcInvalidGMSHInput(line));
2286 in >> line;
2287 }
2288
2289 // if the next block is of kind @f$PartitionedEntities, ignore it
2290 if (line == "@f$PartitionedEntities")
2291 {
2292 do
2293 {
2294 in >> line;
2295 }
2296 while (line != "@f$EndPartitionedEntities");
2297 in >> line;
2298 }
2299
2300 // but the next thing should,
2301 // in any case, be the list of
2302 // nodes:
2303 AssertThrow(line == "@f$Nodes", ExcInvalidGMSHInput(line));
2304 }
2305
2306 // now read the nodes list
2307 int n_entity_blocks = 1;
2308 if (gmsh_file_format > 40)
2309 {
2310 int min_node_tag;
2311 int max_node_tag;
2312 in >> n_entity_blocks >> n_vertices >> min_node_tag >> max_node_tag;
2313 }
2314 else if (gmsh_file_format == 40)
2315 {
2316 in >> n_entity_blocks >> n_vertices;
2317 }
2318 else
2319 in >> n_vertices;
2320 std::vector<Point<spacedim>> vertices(n_vertices);
2321 // set up mapping between numbering
2322 // in msh-file (nod) and in the
2323 // vertices vector
2324 std::map<int, int> vertex_indices;
2325
2326 {
2327 unsigned int global_vertex = 0;
2328 for (int entity_block = 0; entity_block < n_entity_blocks; ++entity_block)
2329 {
2330 int parametric;
2331 unsigned long numNodes;
2332
2333 if (gmsh_file_format < 40)
2334 {
2335 numNodes = n_vertices;
2336 parametric = 0;
2337 }
2338 else
2339 {
2340 // for gmsh_file_format 4.1 the order of tag and dim is reversed,
2341 // but we are ignoring both anyway.
2342 int tagEntity, dimEntity;
2343 in >> tagEntity >> dimEntity >> parametric >> numNodes;
2344 }
2345
2346 std::vector<int> vertex_numbers;
2347 int vertex_number;
2348 if (gmsh_file_format > 40)
2349 for (unsigned long vertex_per_entity = 0;
2350 vertex_per_entity < numNodes;
2351 ++vertex_per_entity)
2352 {
2353 in >> vertex_number;
2354 vertex_numbers.push_back(vertex_number);
2355 }
2356
2357 for (unsigned long vertex_per_entity = 0; vertex_per_entity < numNodes;
2358 ++vertex_per_entity, ++global_vertex)
2359 {
2360 int vertex_number;
2361 double x[3];
2362
2363 // read vertex
2364 if (gmsh_file_format > 40)
2365 {
2366 vertex_number = vertex_numbers[vertex_per_entity];
2367 in >> x[0] >> x[1] >> x[2];
2368 }
2369 else
2370 in >> vertex_number >> x[0] >> x[1] >> x[2];
2371
2372 for (unsigned int d = 0; d < spacedim; ++d)
2373 vertices[global_vertex][d] = x[d];
2374 // store mapping
2375 vertex_indices[vertex_number] = global_vertex;
2376
2377 // ignore parametric coordinates
2378 if (parametric != 0)
2379 {
2380 double u = 0.;
2381 double v = 0.;
2382 in >> u >> v;
2383 (void)u;
2384 (void)v;
2385 }
2386 }
2387 }
2388 AssertDimension(global_vertex, n_vertices);
2389 }
2390
2391 // Assert we reached the end of the block
2392 in >> line;
2393 static const std::string end_nodes_marker[] = {"@f$ENDNOD", "@f$EndNodes"};
2394 AssertThrow(line == end_nodes_marker[gmsh_file_format == 10 ? 0 : 1],
2395 ExcInvalidGMSHInput(line));
2396
2397 // Now read in next bit
2398 in >> line;
2399 static const std::string begin_elements_marker[] = {"@f$ELM", "@f$Elements"};
2400 AssertThrow(line == begin_elements_marker[gmsh_file_format == 10 ? 0 : 1],
2401 ExcInvalidGMSHInput(line));
2402
2403 // now read the cell list
2404 if (gmsh_file_format > 40)
2405 {
2406 int min_node_tag;
2407 int max_node_tag;
2408 in >> n_entity_blocks >> n_cells >> min_node_tag >> max_node_tag;
2409 }
2410 else if (gmsh_file_format == 40)
2411 {
2412 in >> n_entity_blocks >> n_cells;
2413 }
2414 else
2415 {
2416 n_entity_blocks = 1;
2417 in >> n_cells;
2418 }
2419
2420 // set up array of cells and subcells (faces). In 1d, there is currently no
2421 // standard way in deal.II to pass boundary indicators attached to
2422 // individual vertices, so do this by hand via the boundary_ids_1d array
2423 std::vector<CellData<dim>> cells;
2424 SubCellData subcelldata;
2425 std::map<unsigned int, types::boundary_id> boundary_ids_1d;
2426
2427 // Track the number of times each vertex is used in 1D. This determines
2428 // whether or not we can assign a boundary id to a vertex. This is necessary
2429 // because sometimes gmsh saves internal vertices in the @f$ELEM list in codim
2430 // 1 or codim 2.
2431 std::map<unsigned int, unsigned int> vertex_counts;
2432
2433 {
2434 static constexpr std::array<unsigned int, 8> local_vertex_numbering = {
2435 {0, 1, 5, 4, 2, 3, 7, 6}};
2436 unsigned int global_cell = 0;
2437 for (int entity_block = 0; entity_block < n_entity_blocks; ++entity_block)
2438 {
2439 unsigned int material_id;
2440 unsigned long numElements;
2441 int cell_type;
2442
2443 if (gmsh_file_format < 40)
2444 {
2445 material_id = 0;
2446 cell_type = 0;
2447 numElements = n_cells;
2448 }
2449 else if (gmsh_file_format == 40)
2450 {
2451 int tagEntity, dimEntity;
2452 in >> tagEntity >> dimEntity >> cell_type >> numElements;
2453 material_id = tag_maps[dimEntity][tagEntity];
2454 }
2455 else
2456 {
2457 // for gmsh_file_format 4.1 the order of tag and dim is reversed,
2458 int tagEntity, dimEntity;
2459 in >> dimEntity >> tagEntity >> cell_type >> numElements;
2460 material_id = tag_maps[dimEntity][tagEntity];
2461 }
2462
2463 for (unsigned int cell_per_entity = 0; cell_per_entity < numElements;
2464 ++cell_per_entity, ++global_cell)
2465 {
2466 // note that since in the input
2467 // file we found the number of
2468 // cells at the top, there
2469 // should still be input here,
2470 // so check this:
2471 AssertThrow(in.fail() == false, ExcIO());
2472
2473 unsigned int nod_num;
2474
2475 /*
2476 For file format version 1, the format of each cell is as
2477 follows: elm-number elm-type reg-phys reg-elem number-of-nodes
2478 node-number-list
2479
2480 However, for version 2, the format reads like this:
2481 elm-number elm-type number-of-tags < tag > ...
2482 node-number-list
2483
2484 For version 4, we have:
2485 tag(int) numVert(int) ...
2486
2487 In the following, we will ignore the element number (we simply
2488 enumerate them in the order in which we read them, and we will
2489 take reg-phys (version 1) or the first tag (version 2, if any
2490 tag is given at all) as material id. For version 4, we already
2491 read the material and the cell type in above.
2492 */
2493
2494 unsigned int elm_number = 0;
2495 if (gmsh_file_format < 40)
2496 {
2497 in >> elm_number // ELM-NUMBER
2498 >> cell_type; // ELM-TYPE
2499 }
2500
2501 if (gmsh_file_format < 20)
2502 {
2503 in >> material_id // REG-PHYS
2504 >> dummy // reg_elm
2505 >> nod_num;
2506 }
2507 else if (gmsh_file_format < 40)
2508 {
2509 // read the tags; ignore all but the first one which we will
2510 // interpret as the material_id (for cells) or boundary_id
2511 // (for faces)
2512 unsigned int n_tags;
2513 in >> n_tags;
2514 if (n_tags > 0)
2515 in >> material_id;
2516 else
2517 material_id = 0;
2518
2519 for (unsigned int i = 1; i < n_tags; ++i)
2520 in >> dummy;
2521
2522 if (cell_type == 1) // line
2523 nod_num = 2;
2524 else if (cell_type == 2) // tri
2525 nod_num = 3;
2526 else if (cell_type == 3) // quad
2527 nod_num = 4;
2528 else if (cell_type == 4) // tet
2529 nod_num = 4;
2530 else if (cell_type == 5) // hex
2531 nod_num = 8;
2532 }
2533 else // file format version 4.0 and later
2534 {
2535 // ignore tag
2536 int tag;
2537 in >> tag;
2538
2539 if (cell_type == 1) // line
2540 nod_num = 2;
2541 else if (cell_type == 2) // tri
2542 nod_num = 3;
2543 else if (cell_type == 3) // quad
2544 nod_num = 4;
2545 else if (cell_type == 4) // tet
2546 nod_num = 4;
2547 else if (cell_type == 5) // hex
2548 nod_num = 8;
2549 }
2550
2551
2552 /* `ELM-TYPE'
2553 defines the geometrical type of the N-th element:
2554 `1'
2555 Line (2 nodes, 1 edge).
2556
2557 `2'
2558 Triangle (3 nodes, 3 edges).
2559
2560 `3'
2561 Quadrangle (4 nodes, 4 edges).
2562
2563 `4'
2564 Tetrahedron (4 nodes, 6 edges, 6 faces).
2565
2566 `5'
2567 Hexahedron (8 nodes, 12 edges, 6 faces).
2568
2569 `15'
2570 Point (1 node).
2571 */
2572
2573 if (((cell_type == 1) && (dim == 1)) || // a line in 1d
2574 ((cell_type == 2) && (dim == 2)) || // a triangle in 2d
2575 ((cell_type == 3) && (dim == 2)) || // a quadrilateral in 2d
2576 ((cell_type == 4) && (dim == 3)) || // a tet in 3d
2577 ((cell_type == 5) && (dim == 3))) // a hex in 3d
2578 // found a cell
2579 {
2580 unsigned int vertices_per_cell = 0;
2581 if (cell_type == 1) // line
2582 vertices_per_cell = 2;
2583 else if (cell_type == 2) // tri
2584 vertices_per_cell = 3;
2585 else if (cell_type == 3) // quad
2586 vertices_per_cell = 4;
2587 else if (cell_type == 4) // tet
2588 vertices_per_cell = 4;
2589 else if (cell_type == 5) // hex
2590 vertices_per_cell = 8;
2591
2592 AssertThrow(nod_num == vertices_per_cell,
2593 ExcMessage(
2594 "Number of nodes does not coincide with the "
2595 "number required for this object"));
2596
2597 // allocate and read indices
2598 cells.emplace_back();
2599 CellData<dim> &cell = cells.back();
2600 cell.vertices.resize(vertices_per_cell);
2601 for (unsigned int i = 0; i < vertices_per_cell; ++i)
2602 {
2603 // hypercube cells need to be reordered
2604 if (vertices_per_cell ==
2606 in >> cell.vertices[dim == 3 ?
2607 local_vertex_numbering[i] :
2609 else
2610 in >> cell.vertices[i];
2611 }
2612
2613 // to make sure that the cast won't fail
2614 Assert(material_id <=
2615 std::numeric_limits<types::material_id>::max(),
2617 material_id,
2618 0,
2619 std::numeric_limits<types::material_id>::max()));
2620 // we use only material_ids in the range from 0 to
2621 // numbers::invalid_material_id-1
2623
2624 cell.material_id = material_id;
2625
2626 // transform from gmsh to consecutive numbering
2627 for (unsigned int i = 0; i < vertices_per_cell; ++i)
2628 {
2629 AssertThrow(vertex_indices.find(cell.vertices[i]) !=
2630 vertex_indices.end(),
2631 ExcInvalidVertexIndexGmsh(cell_per_entity,
2632 elm_number,
2633 cell.vertices[i]));
2634
2635 const auto vertex = vertex_indices[cell.vertices[i]];
2636 if (dim == 1)
2637 vertex_counts[vertex] += 1u;
2638 cell.vertices[i] = vertex;
2639 }
2640 }
2641 else if ((cell_type == 1) &&
2642 ((dim == 2) || (dim == 3))) // a line in 2d or 3d
2643 // boundary info
2644 {
2645 subcelldata.boundary_lines.emplace_back();
2646 in >> subcelldata.boundary_lines.back().vertices[0] >>
2647 subcelldata.boundary_lines.back().vertices[1];
2648
2649 // to make sure that the cast won't fail
2650 Assert(material_id <=
2651 std::numeric_limits<types::boundary_id>::max(),
2653 material_id,
2654 0,
2655 std::numeric_limits<types::boundary_id>::max()));
2656 // we use only boundary_ids in the range from 0 to
2657 // numbers::internal_face_boundary_id-1
2658 AssertIndexRange(material_id,
2660
2661 subcelldata.boundary_lines.back().boundary_id =
2662 static_cast<types::boundary_id>(material_id);
2663
2664 // transform from ucd to
2665 // consecutive numbering
2666 for (unsigned int &vertex :
2667 subcelldata.boundary_lines.back().vertices)
2668 if (vertex_indices.find(vertex) != vertex_indices.end())
2669 // vertex with this index exists
2670 vertex = vertex_indices[vertex];
2671 else
2672 {
2673 // no such vertex index
2674 AssertThrow(false,
2675 ExcInvalidVertexIndex(cell_per_entity,
2676 vertex));
2678 }
2679 }
2680 else if ((cell_type == 2 || cell_type == 3) &&
2681 (dim == 3)) // a triangle or a quad in 3d
2682 // boundary info
2683 {
2684 unsigned int vertices_per_cell = 0;
2685 // check cell type
2686 if (cell_type == 2) // tri
2687 vertices_per_cell = 3;
2688 else if (cell_type == 3) // quad
2689 vertices_per_cell = 4;
2690
2691 subcelldata.boundary_quads.emplace_back();
2692
2693 // resize vertices
2694 subcelldata.boundary_quads.back().vertices.resize(
2695 vertices_per_cell);
2696 // for loop
2697 for (unsigned int i = 0; i < vertices_per_cell; ++i)
2698 in >> subcelldata.boundary_quads.back().vertices[i];
2699
2700 // to make sure that the cast won't fail
2701 Assert(material_id <=
2702 std::numeric_limits<types::boundary_id>::max(),
2704 material_id,
2705 0,
2706 std::numeric_limits<types::boundary_id>::max()));
2707 // we use only boundary_ids in the range from 0 to
2708 // numbers::internal_face_boundary_id-1
2709 AssertIndexRange(material_id,
2711
2712 subcelldata.boundary_quads.back().boundary_id =
2713 static_cast<types::boundary_id>(material_id);
2714
2715 // transform from gmsh to
2716 // consecutive numbering
2717 for (unsigned int &vertex :
2718 subcelldata.boundary_quads.back().vertices)
2719 if (vertex_indices.find(vertex) != vertex_indices.end())
2720 // vertex with this index exists
2721 vertex = vertex_indices[vertex];
2722 else
2723 {
2724 // no such vertex index
2725 Assert(false,
2726 ExcInvalidVertexIndex(cell_per_entity, vertex));
2728 }
2729 }
2730 else if (cell_type == 15)
2731 {
2732 // read the indices of nodes given
2733 unsigned int node_index = 0;
2734 if (gmsh_file_format < 20)
2735 {
2736 // For points (cell_type==15), we can only ever
2737 // list one node index.
2738 AssertThrow(nod_num == 1, ExcInternalError());
2739 in >> node_index;
2740 }
2741 else
2742 {
2743 in >> node_index;
2744 }
2745
2746 // we only care about boundary indicators assigned to
2747 // individual vertices in 1d (because otherwise the vertices
2748 // are not faces)
2749 if (dim == 1)
2750 boundary_ids_1d[vertex_indices[node_index]] = material_id;
2751 }
2752 else
2753 {
2754 AssertThrow(false, ExcGmshUnsupportedGeometry(cell_type));
2755 }
2756 }
2757 }
2758 AssertDimension(global_cell, n_cells);
2759 }
2760 // Assert that we reached the end of the block
2761 in >> line;
2762 static const std::string end_elements_marker[] = {"@f$ENDELM", "@f$EndElements"};
2763 AssertThrow(line == end_elements_marker[gmsh_file_format == 10 ? 0 : 1],
2764 ExcInvalidGMSHInput(line));
2765 AssertThrow(in.fail() == false, ExcIO());
2766
2767 // check that we actually read some cells.
2768 AssertThrow(cells.size() > 0,
2769 ExcGmshNoCellInformation(subcelldata.boundary_lines.size(),
2770 subcelldata.boundary_quads.size()));
2771
2772 // apply_grid_fixup_functions() may invalidate the vertex indices (since it
2773 // will delete duplicated or unused vertices). Get around this by storing
2774 // Points directly in that case so that the comparisons are valid.
2775 std::vector<std::pair<Point<spacedim>, types::boundary_id>> boundary_id_pairs;
2776 if (dim == 1)
2777 for (const auto &pair : vertex_counts)
2778 if (pair.second == 1u)
2779 boundary_id_pairs.emplace_back(vertices[pair.first],
2780 boundary_ids_1d[pair.first]);
2781
2782 apply_grid_fixup_functions(vertices, cells, subcelldata);
2783 tria->create_triangulation(vertices, cells, subcelldata);
2784
2785 // in 1d, we also have to attach boundary ids to vertices, which does not
2786 // currently work through the call above.
2787 if (dim == 1)
2788 assign_1d_boundary_ids(boundary_id_pairs, *tria);
2789}
2790
2791
2792
2793#ifdef DEAL_II_GMSH_WITH_API
2794template <int dim, int spacedim>
2795void
2796GridIn<dim, spacedim>::read_msh(const std::string &fname)
2797{
2798 Assert(tria != nullptr, ExcNoTriangulationSelected());
2799 // gmsh -> deal.II types
2800 const std::map<int, std::uint8_t> gmsh_to_dealii_type = {
2801 {{15, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}, {7, 5}, {6, 6}, {5, 7}}};
2802
2803 // Vertex renumbering, by dealii type
2804 const std::array<std::vector<unsigned int>, 8> gmsh_to_dealii = {
2805 {{0},
2806 {{0, 1}},
2807 {{0, 1, 2}},
2808 {{0, 1, 3, 2}},
2809 {{0, 1, 2, 3}},
2810 {{0, 1, 3, 2, 4}},
2811 {{0, 1, 2, 3, 4, 5}},
2812 {{0, 1, 3, 2, 4, 5, 7, 6}}}};
2813
2814 std::vector<Point<spacedim>> vertices;
2815 std::vector<CellData<dim>> cells;
2816 SubCellData subcelldata;
2817 std::map<unsigned int, types::boundary_id> boundary_ids_1d;
2818
2819 // Track the number of times each vertex is used in 1D. This determines
2820 // whether or not we can assign a boundary id to a vertex. This is necessary
2821 // because sometimes gmsh saves internal vertices in the @f$ELEM list in codim
2822 // 1 or codim 2.
2823 std::map<unsigned int, unsigned int> vertex_counts;
2824
2825 gmsh::initialize();
2826 gmsh::option::setNumber("General.Verbosity", 0);
2827 gmsh::open(fname);
2828
2829 AssertThrow(gmsh::model::getDimension() == dim,
2830 ExcMessage("You are trying to read a gmsh file with dimension " +
2831 std::to_string(gmsh::model::getDimension()) +
2832 " into a grid of dimension " + std::to_string(dim)));
2833
2834 // Read all nodes, and store them in our vector of vertices. Before we do
2835 // that, make sure all tags are consecutive
2836 {
2837 gmsh::model::mesh::removeDuplicateNodes();
2838 gmsh::model::mesh::renumberNodes();
2839 std::vector<std::size_t> node_tags;
2840 std::vector<double> coord;
2841 std::vector<double> parametricCoord;
2842 gmsh::model::mesh::getNodes(
2843 node_tags, coord, parametricCoord, -1, -1, false, false);
2844 vertices.resize(node_tags.size());
2845 for (unsigned int i = 0; i < node_tags.size(); ++i)
2846 {
2847 // Check that renumbering worked!
2848 AssertDimension(node_tags[i], i + 1);
2849 for (unsigned int d = 0; d < spacedim; ++d)
2850 vertices[i][d] = coord[i * 3 + d];
2851# ifdef DEBUG
2852 // Make sure the embedded dimension is right
2853 for (unsigned int d = spacedim; d < 3; ++d)
2854 Assert(std::abs(coord[i * 3 + d]) < 1e-10,
2855 ExcMessage("The grid you are reading contains nodes that are "
2856 "nonzero in the coordinate with index " +
2857 std::to_string(d) +
2858 ", but you are trying to save "
2859 "it on a grid embedded in a " +
2860 std::to_string(spacedim) + " dimensional space."));
2861# endif
2862 }
2863 }
2864
2865 // Get all the elementary entities in the model, as a vector of (dimension,
2866 // tag) pairs:
2867 std::vector<std::pair<int, int>> entities;
2868 gmsh::model::getEntities(entities);
2869
2870 for (const auto &e : entities)
2871 {
2872 // Dimension and tag of the entity:
2873 const int &entity_dim = e.first;
2874 const int &entity_tag = e.second;
2875
2877 types::boundary_id boundary_id = 0;
2878
2879 // Get the physical tags, to deduce boundary, material, and manifold_id
2880 std::vector<int> physical_tags;
2881 gmsh::model::getPhysicalGroupsForEntity(entity_dim,
2882 entity_tag,
2883 physical_tags);
2884
2885 // Now fill manifold id and boundary or material id
2886 if (physical_tags.size())
2887 for (auto physical_tag : physical_tags)
2888 {
2889 std::string name;
2890 gmsh::model::getPhysicalName(entity_dim, physical_tag, name);
2891 if (!name.empty())
2892 {
2893 // Patterns::Tools::to_value throws an exception, if it can not
2894 // convert name to a map from string to int.
2895 try
2896 {
2897 std::map<std::string, int> id_names;
2898 Patterns::Tools::to_value(name, id_names);
2899 bool found_unrecognized_tag = false;
2900 bool found_boundary_id = false;
2901 // If the above did not throw, we keep going, and retrieve
2902 // all the information that we know how to translate.
2903 for (const auto &it : id_names)
2904 {
2905 const auto &name = it.first;
2906 const auto &id = it.second;
2907 if (entity_dim == dim && name == "MaterialID")
2908 {
2909 boundary_id = static_cast<types::boundary_id>(id);
2910 found_boundary_id = true;
2911 }
2912 else if (entity_dim < dim && name == "BoundaryID")
2913 {
2914 boundary_id = static_cast<types::boundary_id>(id);
2915 found_boundary_id = true;
2916 }
2917 else if (name == "ManifoldID")
2918 manifold_id = static_cast<types::manifold_id>(id);
2919 else
2920 // We did not recognize one of the keys. We'll fall
2921 // back to setting the boundary id to the physical tag
2922 // after reading all strings.
2923 found_unrecognized_tag = true;
2924 }
2925 // If we didn't find a BoundaryID:XX or MaterialID:XX, and
2926 // something was found but not recognized, then we set the
2927 // material id or boundary using the physical tag directly.
2928 if (found_unrecognized_tag && !found_boundary_id)
2929 boundary_id = physical_tag;
2930 }
2931 catch (...)
2932 {
2933 // When the above didn't work, we revert to the old
2934 // behaviour: the physical tag itself is interpreted either
2935 // as a material_id or a boundary_id, and no manifold id is
2936 // known
2937 boundary_id = physical_tag;
2938 }
2939 }
2940 }
2941
2942 // Get the mesh elements for the entity (dim, tag):
2943 std::vector<int> element_types;
2944 std::vector<std::vector<std::size_t>> element_ids, element_nodes;
2945 gmsh::model::mesh::getElements(
2946 element_types, element_ids, element_nodes, entity_dim, entity_tag);
2947
2948 for (unsigned int i = 0; i < element_types.size(); ++i)
2949 {
2950 const auto &type = gmsh_to_dealii_type.at(element_types[i]);
2951 const auto n_vertices = gmsh_to_dealii[type].size();
2952 const auto &elements = element_ids[i];
2953 const auto &nodes = element_nodes[i];
2954 for (unsigned int j = 0; j < elements.size(); ++j)
2955 {
2956 if (entity_dim == dim)
2957 {
2958 cells.emplace_back(n_vertices);
2959 auto &cell = cells.back();
2960 for (unsigned int v = 0; v < n_vertices; ++v)
2961 {
2962 cell.vertices[v] =
2963 nodes[n_vertices * j + gmsh_to_dealii[type][v]] - 1;
2964 if (dim == 1)
2965 vertex_counts[cell.vertices[v]] += 1u;
2966 }
2967 cell.manifold_id = manifold_id;
2968 cell.material_id = boundary_id;
2969 }
2970 else if (entity_dim == 2)
2971 {
2972 subcelldata.boundary_quads.emplace_back(n_vertices);
2973 auto &face = subcelldata.boundary_quads.back();
2974 for (unsigned int v = 0; v < n_vertices; ++v)
2975 face.vertices[v] =
2976 nodes[n_vertices * j + gmsh_to_dealii[type][v]] - 1;
2977
2978 face.manifold_id = manifold_id;
2979 face.boundary_id = boundary_id;
2980 }
2981 else if (entity_dim == 1)
2982 {
2983 subcelldata.boundary_lines.emplace_back(n_vertices);
2984 auto &line = subcelldata.boundary_lines.back();
2985 for (unsigned int v = 0; v < n_vertices; ++v)
2986 line.vertices[v] =
2987 nodes[n_vertices * j + gmsh_to_dealii[type][v]] - 1;
2988
2989 line.manifold_id = manifold_id;
2990 line.boundary_id = boundary_id;
2991 }
2992 else if (entity_dim == 0)
2993 {
2994 // This should only happen in one dimension.
2995 AssertDimension(dim, 1);
2996 for (unsigned int j = 0; j < elements.size(); ++j)
2997 boundary_ids_1d[nodes[j] - 1] = boundary_id;
2998 }
2999 }
3000 }
3001 }
3002
3003 // apply_grid_fixup_functions() may invalidate the vertex indices (since it
3004 // will delete duplicated or unused vertices). Get around this by storing
3005 // Points directly in that case so that the comparisons are valid.
3006 std::vector<std::pair<Point<spacedim>, types::boundary_id>> boundary_id_pairs;
3007 if (dim == 1)
3008 for (const auto &pair : vertex_counts)
3009 if (pair.second == 1u)
3010 boundary_id_pairs.emplace_back(vertices[pair.first],
3011 boundary_ids_1d[pair.first]);
3012
3013 apply_grid_fixup_functions(vertices, cells, subcelldata);
3014 tria->create_triangulation(vertices, cells, subcelldata);
3015
3016 // in 1d, we also have to attach boundary ids to vertices, which does not
3017 // currently work through the call above.
3018 if (dim == 1)
3019 assign_1d_boundary_ids(boundary_id_pairs, *tria);
3020
3021 gmsh::clear();
3022 gmsh::finalize();
3023}
3024#endif
3025
3026
3027
3028template <int dim, int spacedim>
3029void
3031 std::string &header,
3032 std::vector<unsigned int> &tecplot2deal,
3033 unsigned int &n_vars,
3034 unsigned int &n_vertices,
3035 unsigned int &n_cells,
3036 std::vector<unsigned int> &IJK,
3037 bool &structured,
3038 bool &blocked)
3039{
3040 Assert(tecplot2deal.size() == dim, ExcInternalError());
3041 Assert(IJK.size() == dim, ExcInternalError());
3042 // initialize the output variables
3043 n_vars = 0;
3044 n_vertices = 0;
3045 n_cells = 0;
3046 switch (dim)
3047 {
3048 case 3:
3049 IJK[2] = 0;
3051 case 2:
3052 IJK[1] = 0;
3054 case 1:
3055 IJK[0] = 0;
3056 }
3057 structured = true;
3058 blocked = false;
3059
3060 // convert the string to upper case
3061 std::transform(header.begin(), header.end(), header.begin(), ::toupper);
3062
3063 // replace all tabs, commas, newlines by
3064 // whitespaces
3065 std::replace(header.begin(), header.end(), '\t', ' ');
3066 std::replace(header.begin(), header.end(), ',', ' ');
3067 std::replace(header.begin(), header.end(), '\n', ' ');
3068
3069 // now remove whitespace in front of and
3070 // after '='
3071 std::string::size_type pos = header.find('=');
3072
3073 while (pos != static_cast<std::string::size_type>(std::string::npos))
3074 if (header[pos + 1] == ' ')
3075 header.erase(pos + 1, 1);
3076 else if (header[pos - 1] == ' ')
3077 {
3078 header.erase(pos - 1, 1);
3079 --pos;
3080 }
3081 else
3082 pos = header.find('=', ++pos);
3083
3084 // split the string into individual entries
3085 std::vector<std::string> entries =
3086 Utilities::break_text_into_lines(header, 1, ' ');
3087
3088 // now go through the list and try to extract
3089 for (unsigned int i = 0; i < entries.size(); ++i)
3090 {
3091 if (Utilities::match_at_string_start(entries[i], "VARIABLES=\""))
3092 {
3093 ++n_vars;
3094 // we assume, that the first variable
3095 // is x or no coordinate at all (not y or z)
3096 if (Utilities::match_at_string_start(entries[i], "VARIABLES=\"X\""))
3097 {
3098 tecplot2deal[0] = 0;
3099 }
3100 ++i;
3101 while (entries[i][0] == '"')
3102 {
3103 if (entries[i] == "\"X\"")
3104 tecplot2deal[0] = n_vars;
3105 else if (entries[i] == "\"Y\"")
3106 {
3107 // we assume, that y contains
3108 // zero data in 1d, so do
3109 // nothing
3110 if (dim > 1)
3111 tecplot2deal[1] = n_vars;
3112 }
3113 else if (entries[i] == "\"Z\"")
3114 {
3115 // we assume, that z contains
3116 // zero data in 1d and 2d, so
3117 // do nothing
3118 if (dim > 2)
3119 tecplot2deal[2] = n_vars;
3120 }
3121 ++n_vars;
3122 ++i;
3123 }
3124 // set i back, so that the next
3125 // string is treated correctly
3126 --i;
3127
3129 n_vars >= dim,
3130 ExcMessage(
3131 "Tecplot file must contain at least one variable for each dimension"));
3132 for (unsigned int d = 1; d < dim; ++d)
3134 tecplot2deal[d] > 0,
3135 ExcMessage(
3136 "Tecplot file must contain at least one variable for each dimension."));
3137 }
3138 else if (Utilities::match_at_string_start(entries[i], "ZONETYPE=ORDERED"))
3139 structured = true;
3140 else if (Utilities::match_at_string_start(entries[i],
3141 "ZONETYPE=FELINESEG") &&
3142 dim == 1)
3143 structured = false;
3144 else if (Utilities::match_at_string_start(entries[i],
3145 "ZONETYPE=FEQUADRILATERAL") &&
3146 dim == 2)
3147 structured = false;
3148 else if (Utilities::match_at_string_start(entries[i],
3149 "ZONETYPE=FEBRICK") &&
3150 dim == 3)
3151 structured = false;
3152 else if (Utilities::match_at_string_start(entries[i], "ZONETYPE="))
3153 // unsupported ZONETYPE
3154 {
3155 AssertThrow(false,
3156 ExcMessage(
3157 "The tecplot file contains an unsupported ZONETYPE."));
3158 }
3159 else if (Utilities::match_at_string_start(entries[i],
3160 "DATAPACKING=POINT"))
3161 blocked = false;
3162 else if (Utilities::match_at_string_start(entries[i],
3163 "DATAPACKING=BLOCK"))
3164 blocked = true;
3165 else if (Utilities::match_at_string_start(entries[i], "F=POINT"))
3166 {
3167 structured = true;
3168 blocked = false;
3169 }
3170 else if (Utilities::match_at_string_start(entries[i], "F=BLOCK"))
3171 {
3172 structured = true;
3173 blocked = true;
3174 }
3175 else if (Utilities::match_at_string_start(entries[i], "F=FEPOINT"))
3176 {
3177 structured = false;
3178 blocked = false;
3179 }
3180 else if (Utilities::match_at_string_start(entries[i], "F=FEBLOCK"))
3181 {
3182 structured = false;
3183 blocked = true;
3184 }
3185 else if (Utilities::match_at_string_start(entries[i],
3186 "ET=QUADRILATERAL") &&
3187 dim == 2)
3188 structured = false;
3189 else if (Utilities::match_at_string_start(entries[i], "ET=BRICK") &&
3190 dim == 3)
3191 structured = false;
3192 else if (Utilities::match_at_string_start(entries[i], "ET="))
3193 // unsupported ElementType
3194 {
3196 false,
3197 ExcMessage(
3198 "The tecplot file contains an unsupported ElementType."));
3199 }
3200 else if (Utilities::match_at_string_start(entries[i], "I="))
3201 IJK[0] = Utilities::get_integer_at_position(entries[i], 2).first;
3202 else if (Utilities::match_at_string_start(entries[i], "J="))
3203 {
3204 IJK[1] = Utilities::get_integer_at_position(entries[i], 2).first;
3206 dim > 1 || IJK[1] == 1,
3207 ExcMessage(
3208 "Parameter 'J=' found in tecplot, although this is only possible for dimensions greater than 1."));
3209 }
3210 else if (Utilities::match_at_string_start(entries[i], "K="))
3211 {
3212 IJK[2] = Utilities::get_integer_at_position(entries[i], 2).first;
3214 dim > 2 || IJK[2] == 1,
3215 ExcMessage(
3216 "Parameter 'K=' found in tecplot, although this is only possible for dimensions greater than 2."));
3217 }
3218 else if (Utilities::match_at_string_start(entries[i], "N="))
3219 n_vertices = Utilities::get_integer_at_position(entries[i], 2).first;
3220 else if (Utilities::match_at_string_start(entries[i], "E="))
3221 n_cells = Utilities::get_integer_at_position(entries[i], 2).first;
3222 }
3223
3224 // now we have read all the fields we are
3225 // interested in. do some checks and
3226 // calculate the variables
3227 if (structured)
3228 {
3229 n_vertices = 1;
3230 n_cells = 1;
3231 for (unsigned int d = 0; d < dim; ++d)
3232 {
3234 IJK[d] > 0,
3235 ExcMessage(
3236 "Tecplot file does not contain a complete and consistent set of parameters"));
3237 n_vertices *= IJK[d];
3238 n_cells *= (IJK[d] - 1);
3239 }
3240 }
3241 else
3242 {
3244 n_vertices > 0,
3245 ExcMessage(
3246 "Tecplot file does not contain a complete and consistent set of parameters"));
3247 if (n_cells == 0)
3248 // this means an error, although
3249 // tecplot itself accepts entries like
3250 // 'J=20' instead of 'E=20'. therefore,
3251 // take the max of IJK
3252 n_cells = *std::max_element(IJK.begin(), IJK.end());
3254 n_cells > 0,
3255 ExcMessage(
3256 "Tecplot file does not contain a complete and consistent set of parameters"));
3257 }
3258}
3259
3260
3261
3262template <>
3263void
3265{
3266 const unsigned int dim = 2;
3267 const unsigned int spacedim = 2;
3268 Assert(tria != nullptr, ExcNoTriangulationSelected());
3269 AssertThrow(in.fail() == false, ExcIO());
3270
3271 // skip comments at start of file
3272 skip_comment_lines(in, '#');
3273
3274 // some strings for parsing the header
3275 std::string line, header;
3276
3277 // first, concatenate all header lines
3278 // create a searchstring with almost all
3279 // letters. exclude e and E from the letters
3280 // to search, as they might appear in
3281 // exponential notation
3282 std::string letters = "abcdfghijklmnopqrstuvwxyzABCDFGHIJKLMNOPQRSTUVWXYZ";
3283
3284 getline(in, line);
3285 while (line.find_first_of(letters) != std::string::npos)
3286 {
3287 header += " " + line;
3288 getline(in, line);
3289 }
3290
3291 // now create some variables holding
3292 // important information on the mesh, get
3293 // this information from the header string
3294 std::vector<unsigned int> tecplot2deal(dim);
3295 std::vector<unsigned int> IJK(dim);
3296 unsigned int n_vars, n_vertices, n_cells;
3297 bool structured, blocked;
3298
3299 parse_tecplot_header(header,
3300 tecplot2deal,
3301 n_vars,
3302 n_vertices,
3303 n_cells,
3304 IJK,
3305 structured,
3306 blocked);
3307
3308 // reserve space for vertices. note, that in
3309 // tecplot vertices are ordered beginning
3310 // with 1, whereas in deal all indices start
3311 // with 0. in order not to use -1 for all the
3312 // connectivity information, a 0th vertex
3313 // (unused) is inserted at the origin.
3314 std::vector<Point<spacedim>> vertices(n_vertices + 1);
3315 vertices[0] = Point<spacedim>();
3316 // reserve space for cells
3317 std::vector<CellData<dim>> cells(n_cells);
3318 SubCellData subcelldata;
3319
3320 if (blocked)
3321 {
3322 // blocked data format. first we get all
3323 // the values of the first variable for
3324 // all points, after that we get all
3325 // values for the second variable and so
3326 // on.
3327
3328 // dummy variable to read in all the info
3329 // we do not want to use
3330 double dummy;
3331 // which is the first index to read in
3332 // the loop (see below)
3333 unsigned int next_index = 0;
3334
3335 // note, that we have already read the
3336 // first line containing the first variable
3337 if (tecplot2deal[0] == 0)
3338 {
3339 // we need the information in this
3340 // line, so extract it
3341 std::vector<std::string> first_var =
3343 char *endptr;
3344 for (unsigned int i = 1; i < first_var.size() + 1; ++i)
3345 vertices[i][0] = std::strtod(first_var[i - 1].c_str(), &endptr);
3346
3347 // if there are many points, the data
3348 // for this var might continue in the
3349 // next line(s)
3350 for (unsigned int j = first_var.size() + 1; j < n_vertices + 1; ++j)
3351 in >> vertices[j][next_index];
3352 // now we got all values of the first
3353 // variable, so increase the counter
3354 next_index = 1;
3355 }
3356
3357 // main loop over all variables
3358 for (unsigned int i = 1; i < n_vars; ++i)
3359 {
3360 // if we read all the important
3361 // variables and do not want to
3362 // read further, because we are
3363 // using a structured grid, we can
3364 // stop here (and skip, for
3365 // example, a whole lot of solution
3366 // variables)
3367 if (next_index == dim && structured)
3368 break;
3369
3370 if ((next_index < dim) && (i == tecplot2deal[next_index]))
3371 {
3372 // we need this line, read it in
3373 for (unsigned int j = 1; j < n_vertices + 1; ++j)
3374 in >> vertices[j][next_index];
3375 ++next_index;
3376 }
3377 else
3378 {
3379 // we do not need this line, read
3380 // it in and discard it
3381 for (unsigned int j = 1; j < n_vertices + 1; ++j)
3382 in >> dummy;
3383 }
3384 }
3385 Assert(next_index == dim, ExcInternalError());
3386 }
3387 else
3388 {
3389 // the data is not blocked, so we get all
3390 // the variables for one point, then the
3391 // next and so on. create a vector to
3392 // hold these components
3393 std::vector<double> vars(n_vars);
3394
3395 // now fill the first vertex. note, that we
3396 // have already read the first line
3397 // containing the first vertex
3398 std::vector<std::string> first_vertex =
3400 char *endptr;
3401 for (unsigned int d = 0; d < dim; ++d)
3402 vertices[1][d] =
3403 std::strtod(first_vertex[tecplot2deal[d]].c_str(), &endptr);
3404
3405 // read the remaining vertices from the
3406 // list
3407 for (unsigned int v = 2; v < n_vertices + 1; ++v)
3408 {
3409 for (unsigned int i = 0; i < n_vars; ++i)
3410 in >> vars[i];
3411 // fill the vertex
3412 // coordinates. respect the position
3413 // of coordinates in the list of
3414 // variables
3415 for (unsigned int i = 0; i < dim; ++i)
3416 vertices[v][i] = vars[tecplot2deal[i]];
3417 }
3418 }
3419
3420 if (structured)
3421 {
3422 // this is the part of the code that only
3423 // works in 2d
3424 unsigned int I = IJK[0], J = IJK[1];
3425
3426 unsigned int cell = 0;
3427 // set up array of cells
3428 for (unsigned int j = 0; j < J - 1; ++j)
3429 for (unsigned int i = 1; i < I; ++i)
3430 {
3431 cells[cell].vertices[0] = i + j * I;
3432 cells[cell].vertices[1] = i + 1 + j * I;
3433 cells[cell].vertices[2] = i + (j + 1) * I;
3434 cells[cell].vertices[3] = i + 1 + (j + 1) * I;
3435 ++cell;
3436 }
3437 Assert(cell == n_cells, ExcInternalError());
3438 std::vector<unsigned int> boundary_vertices(2 * I + 2 * J - 4);
3439 unsigned int k = 0;
3440 for (unsigned int i = 1; i < I + 1; ++i)
3441 {
3442 boundary_vertices[k] = i;
3443 ++k;
3444 boundary_vertices[k] = i + (J - 1) * I;
3445 ++k;
3446 }
3447 for (unsigned int j = 1; j < J - 1; ++j)
3448 {
3449 boundary_vertices[k] = 1 + j * I;
3450 ++k;
3451 boundary_vertices[k] = I + j * I;
3452 ++k;
3453 }
3454 Assert(k == boundary_vertices.size(), ExcInternalError());
3455 // delete the duplicated vertices at the
3456 // boundary, which occur, e.g. in c-type
3457 // or o-type grids around a body
3458 // (airfoil). this automatically deletes
3459 // unused vertices as well.
3461 cells,
3462 subcelldata,
3463 boundary_vertices);
3464 }
3465 else
3466 {
3467 // set up array of cells, unstructured
3468 // mode, so the connectivity is
3469 // explicitly given
3470 for (unsigned int i = 0; i < n_cells; ++i)
3471 {
3472 // note that since in the input file
3473 // we found the number of cells at
3474 // the top, there should still be
3475 // input here, so check this:
3476 AssertThrow(in.fail() == false, ExcIO());
3477
3478 // get the connectivity from the
3479 // input file. the vertices are
3480 // ordered like in the ucd format
3481 for (const unsigned int j : GeometryInfo<dim>::vertex_indices())
3482 in >> cells[i].vertices[GeometryInfo<dim>::ucd_to_deal[j]];
3483 }
3484 }
3485 AssertThrow(in.fail() == false, ExcIO());
3486
3487 apply_grid_fixup_functions(vertices, cells, subcelldata);
3488 tria->create_triangulation(vertices, cells, subcelldata);
3489}
3490
3491
3492
3493template <int dim, int spacedim>
3494void
3499
3500
3501
3502template <int dim, int spacedim>
3503void
3504GridIn<dim, spacedim>::read_assimp(const std::string &filename,
3505 const unsigned int mesh_index,
3506 const bool remove_duplicates,
3507 const double tol,
3508 const bool ignore_unsupported_types)
3509{
3510#ifdef DEAL_II_WITH_ASSIMP
3511 // Only good for surface grids.
3512 AssertThrow(dim < 3, ExcImpossibleInDim(dim));
3513
3514 // Create an instance of the Importer class
3515 Assimp::Importer importer;
3516
3517 // And have it read the given file with some postprocessing
3518 const aiScene *scene =
3519 importer.ReadFile(filename.c_str(),
3520 aiProcess_RemoveComponent |
3521 aiProcess_JoinIdenticalVertices |
3522 aiProcess_ImproveCacheLocality | aiProcess_SortByPType |
3523 aiProcess_OptimizeGraph | aiProcess_OptimizeMeshes);
3524
3525 // If the import failed, report it
3526 AssertThrow(scene != nullptr, ExcMessage(importer.GetErrorString()));
3527
3528 AssertThrow(scene->mNumMeshes != 0,
3529 ExcMessage("Input file contains no meshes."));
3530
3532 (mesh_index < scene->mNumMeshes),
3533 ExcMessage("Too few meshes in the file."));
3534
3535 unsigned int start_mesh =
3536 (mesh_index == numbers::invalid_unsigned_int ? 0 : mesh_index);
3537 unsigned int end_mesh =
3538 (mesh_index == numbers::invalid_unsigned_int ? scene->mNumMeshes :
3539 mesh_index + 1);
3540
3541 // Deal.II objects are created empty, and then filled with imported file.
3542 std::vector<Point<spacedim>> vertices;
3543 std::vector<CellData<dim>> cells;
3544 SubCellData subcelldata;
3545
3546 // A series of counters to merge cells.
3547 unsigned int v_offset = 0;
3548 unsigned int c_offset = 0;
3549
3550 static constexpr std::array<unsigned int, 8> local_vertex_numbering = {
3551 {0, 1, 5, 4, 2, 3, 7, 6}};
3552 // The index of the mesh will be used as a material index.
3553 for (unsigned int m = start_mesh; m < end_mesh; ++m)
3554 {
3555 const aiMesh *mesh = scene->mMeshes[m];
3556
3557 // Check that we know what to do with this mesh, otherwise just
3558 // ignore it
3559 if ((dim == 2) && mesh->mPrimitiveTypes != aiPrimitiveType_POLYGON)
3560 {
3561 AssertThrow(ignore_unsupported_types,
3562 ExcMessage("Incompatible mesh " + std::to_string(m) +
3563 "/" + std::to_string(scene->mNumMeshes)));
3564 continue;
3565 }
3566 else if ((dim == 1) && mesh->mPrimitiveTypes != aiPrimitiveType_LINE)
3567 {
3568 AssertThrow(ignore_unsupported_types,
3569 ExcMessage("Incompatible mesh " + std::to_string(m) +
3570 "/" + std::to_string(scene->mNumMeshes)));
3571 continue;
3572 }
3573 // Vertices
3574 const unsigned int n_vertices = mesh->mNumVertices;
3575 const aiVector3D *mVertices = mesh->mVertices;
3576
3577 // Faces
3578 const unsigned int n_faces = mesh->mNumFaces;
3579 const aiFace *mFaces = mesh->mFaces;
3580
3581 vertices.resize(v_offset + n_vertices);
3582 cells.resize(c_offset + n_faces);
3583
3584 for (unsigned int i = 0; i < n_vertices; ++i)
3585 for (unsigned int d = 0; d < spacedim; ++d)
3586 vertices[i + v_offset][d] = mVertices[i][d];
3587
3588 unsigned int valid_cell = c_offset;
3589 for (unsigned int i = 0; i < n_faces; ++i)
3590 {
3591 if (mFaces[i].mNumIndices == GeometryInfo<dim>::vertices_per_cell)
3592 {
3593 for (const unsigned int f : GeometryInfo<dim>::vertex_indices())
3594 {
3595 cells[valid_cell]
3596 .vertices[dim == 3 ? local_vertex_numbering[f] :
3598 mFaces[i].mIndices[f] + v_offset;
3599 }
3600 cells[valid_cell].material_id = m;
3601 ++valid_cell;
3602 }
3603 else
3604 {
3605 AssertThrow(ignore_unsupported_types,
3606 ExcMessage("Face " + std::to_string(i) + " of mesh " +
3607 std::to_string(m) + " has " +
3608 std::to_string(mFaces[i].mNumIndices) +
3609 " vertices. We expected only " +
3610 std::to_string(
3612 }
3613 }
3614 cells.resize(valid_cell);
3615
3616 // The vertices are added all at once. Cells are checked for
3617 // validity, so only valid_cells are now present in the deal.II
3618 // list of cells.
3619 v_offset += n_vertices;
3620 c_offset = valid_cell;
3621 }
3622
3623 // No cells were read
3624 if (cells.empty())
3625 return;
3626
3627 if (remove_duplicates)
3628 {
3629 // The function delete_duplicated_vertices() needs to be called more
3630 // than once if a vertex is duplicated more than once. So we keep
3631 // calling it until the number of vertices does not change any more.
3632 unsigned int n_verts = 0;
3633 while (n_verts != vertices.size())
3634 {
3635 n_verts = vertices.size();
3636 std::vector<unsigned int> considered_vertices;
3638 vertices, cells, subcelldata, considered_vertices, tol);
3639 }
3640 }
3641
3642 apply_grid_fixup_functions(vertices, cells, subcelldata);
3643 tria->create_triangulation(vertices, cells, subcelldata);
3644
3645#else
3646 (void)filename;
3647 (void)mesh_index;
3648 (void)remove_duplicates;
3649 (void)tol;
3650 (void)ignore_unsupported_types;
3651 AssertThrow(false, ExcNeedsAssimp());
3652#endif
3653}
3654
3655#ifdef DEAL_II_TRILINOS_WITH_SEACAS
3656// Namespace containing some extra functions for reading ExodusII files
3657namespace
3658{
3659 // Convert ExodusII strings to cell types. Use the number of nodes per
3660 // element to disambiguate some cases.
3662 exodusii_name_to_type(const std::string &type_name,
3663 const int n_nodes_per_element)
3664 {
3665 Assert(type_name.size() > 0, ExcInternalError());
3666 // Try to canonify the name by switching to upper case and removing
3667 // trailing numbers. This makes, e.g., pyramid, PYRAMID, PYRAMID5, and
3668 // PYRAMID13 all equal.
3669 std::string type_name_2 = type_name;
3670 std::transform(type_name_2.begin(),
3671 type_name_2.end(),
3672 type_name_2.begin(),
3673 [](unsigned char c) { return std::toupper(c); });
3674 const std::string numbers = "0123456789";
3675 type_name_2.erase(std::find_first_of(type_name_2.begin(),
3676 type_name_2.end(),
3677 numbers.begin(),
3678 numbers.end()),
3679 type_name_2.end());
3680
3681 // The manual specifies BAR, BEAM, and TRUSS: in practice people use EDGE
3682 if (type_name_2 == "BAR" || type_name_2 == "BEAM" ||
3683 type_name_2 == "EDGE" || type_name_2 == "TRUSS")
3684 return ReferenceCells::Line;
3685 else if (type_name_2 == "TRI" || type_name_2 == "TRIANGLE")
3687 else if (type_name_2 == "QUAD" || type_name_2 == "QUADRILATERAL")
3689 else if (type_name_2 == "SHELL")
3690 {
3691 if (n_nodes_per_element == 3)
3693 else
3695 }
3696 else if (type_name_2 == "TET" || type_name_2 == "TETRA" ||
3697 type_name_2 == "TETRAHEDRON")
3699 else if (type_name_2 == "PYRA" || type_name_2 == "PYRAMID")
3701 else if (type_name_2 == "WEDGE")
3702 return ReferenceCells::Wedge;
3703 else if (type_name_2 == "HEX" || type_name_2 == "HEXAHEDRON")
3705
3708 }
3709
3710 // Associate deal.II boundary ids with sidesets (a face can be in multiple
3711 // sidesets - to translate we assign each set of side set ids to a
3712 // boundary_id or manifold_id)
3713 template <int dim, int spacedim = dim>
3714 std::pair<SubCellData, std::vector<std::vector<int>>>
3715 read_exodusii_sidesets(const int ex_id,
3716 const int n_side_sets,
3717 const std::vector<CellData<dim>> &cells,
3718 const bool apply_all_indicators_to_manifolds)
3719 {
3720 SubCellData subcelldata;
3721 std::vector<std::vector<int>> b_or_m_id_to_sideset_ids;
3722 // boundary id 0 is the default
3723 b_or_m_id_to_sideset_ids.emplace_back();
3724 // deal.II does not support assigning boundary ids with nonzero
3725 // codimension meshes so completely skip this information in that case.
3726 //
3727 // Exodus prints warnings if we try to get empty sets so always check
3728 // first
3729 if (dim == spacedim && n_side_sets > 0)
3730 {
3731 std::vector<int> side_set_ids(n_side_sets);
3732 int ierr = ex_get_ids(ex_id, EX_SIDE_SET, side_set_ids.data());
3733 AssertThrowExodusII(ierr);
3734
3735 // First collect all side sets on all boundary faces (indexed here as
3736 // max_faces_per_cell * cell_n + face_n). We then sort and uniquify
3737 // the side sets so that we can convert a set of side set indices into
3738 // a single deal.II boundary or manifold id (and save the
3739 // correspondence).
3740 std::map<std::size_t, std::vector<int>> face_side_sets;
3741 for (const int side_set_id : side_set_ids)
3742 {
3743 int n_sides = -1;
3744 int n_distribution_factors = -1;
3745
3746 ierr = ex_get_set_param(ex_id,
3747 EX_SIDE_SET,
3748 side_set_id,
3749 &n_sides,
3750 &n_distribution_factors);
3751 AssertThrowExodusII(ierr);
3752 if (n_sides > 0)
3753 {
3754 std::vector<int> elements(n_sides);
3755 std::vector<int> faces(n_sides);
3756 ierr = ex_get_set(ex_id,
3757 EX_SIDE_SET,
3758 side_set_id,
3759 elements.data(),
3760 faces.data());
3761 AssertThrowExodusII(ierr);
3762
3763 // According to the manual (subsection 4.8): "The internal
3764 // number of an element numbering is defined implicitly by the
3765 // order in which it appears in the file. Elements are
3766 // numbered internally (beginning with 1) consecutively across
3767 // all element blocks." Hence element i in Exodus numbering is
3768 // entry i - 1 in the cells array.
3769 for (int side_n = 0; side_n < n_sides; ++side_n)
3770 {
3771 const long element_n = elements[side_n] - 1;
3772 const long face_n = faces[side_n] - 1;
3773 const std::size_t face_id =
3774 element_n * ReferenceCells::max_n_faces<dim>() + face_n;
3775 face_side_sets[face_id].push_back(side_set_id);
3776 }
3777 }
3778 }
3779
3780 // Collect into a sortable data structure:
3781 std::vector<std::pair<std::size_t, std::vector<int>>>
3782 face_id_to_side_sets;
3783 face_id_to_side_sets.reserve(face_side_sets.size());
3784 for (auto &pair : face_side_sets)
3785 {
3786 Assert(pair.second.size() > 0, ExcInternalError());
3787 face_id_to_side_sets.emplace_back(std::move(pair));
3788 }
3789
3790 // sort by side sets:
3791 std::sort(face_id_to_side_sets.begin(),
3792 face_id_to_side_sets.end(),
3793 [](const auto &a, const auto &b) {
3794 return std::lexicographical_compare(a.second.begin(),
3795 a.second.end(),
3796 b.second.begin(),
3797 b.second.end());
3798 });
3799
3800 if (dim == 2)
3801 subcelldata.boundary_lines.reserve(face_id_to_side_sets.size());
3802 else if (dim == 3)
3803 subcelldata.boundary_quads.reserve(face_id_to_side_sets.size());
3804 types::boundary_id current_b_or_m_id = 0;
3805 for (const auto &pair : face_id_to_side_sets)
3806 {
3807 const std::size_t face_id = pair.first;
3808 const std::vector<int> &face_sideset_ids = pair.second;
3809 if (face_sideset_ids != b_or_m_id_to_sideset_ids.back())
3810 {
3811 // Since we sorted by sideset ids we are guaranteed that if
3812 // this doesn't match the last set then it has not yet been
3813 // seen
3814 ++current_b_or_m_id;
3815 b_or_m_id_to_sideset_ids.push_back(face_sideset_ids);
3816 Assert(current_b_or_m_id == b_or_m_id_to_sideset_ids.size() - 1,
3818 }
3819 // Record the b_or_m_id of the current face.
3820 const unsigned int local_face_n =
3821 face_id % ReferenceCells::max_n_faces<dim>();
3822 const CellData<dim> &cell =
3823 cells[face_id / ReferenceCells::max_n_faces<dim>()];
3824 const ReferenceCell cell_type =
3826 const unsigned int deal_face_n =
3827 cell_type.exodusii_face_to_deal_face(local_face_n);
3828 const ReferenceCell face_reference_cell =
3829 cell_type.face_reference_cell(deal_face_n);
3830
3831 // The orientation we pick doesn't matter here since when we
3832 // create the Triangulation we will sort the vertices for each
3833 // CellData object created here.
3834 if (dim == 2)
3835 {
3836 CellData<1> boundary_line(face_reference_cell.n_vertices());
3837 if (apply_all_indicators_to_manifolds)
3838 boundary_line.manifold_id = current_b_or_m_id;
3839 else
3840 boundary_line.boundary_id = current_b_or_m_id;
3841 for (unsigned int j = 0; j < face_reference_cell.n_vertices();
3842 ++j)
3843 boundary_line.vertices[j] =
3844 cell.vertices[cell_type.face_to_cell_vertices(
3845 deal_face_n, j, 0)];
3846
3847 subcelldata.boundary_lines.push_back(std::move(boundary_line));
3848 }
3849 else if (dim == 3)
3850 {
3851 CellData<2> boundary_quad(face_reference_cell.n_vertices());
3852 if (apply_all_indicators_to_manifolds)
3853 boundary_quad.manifold_id = current_b_or_m_id;
3854 else
3855 boundary_quad.boundary_id = current_b_or_m_id;
3856 for (unsigned int j = 0; j < face_reference_cell.n_vertices();
3857 ++j)
3858 boundary_quad.vertices[j] =
3859 cell.vertices[cell_type.face_to_cell_vertices(
3860 deal_face_n, j, 0)];
3861
3862 subcelldata.boundary_quads.push_back(std::move(boundary_quad));
3863 }
3864 }
3865 }
3866
3867 return std::make_pair(std::move(subcelldata),
3868 std::move(b_or_m_id_to_sideset_ids));
3869 }
3870} // namespace
3871#endif
3872
3873template <int dim, int spacedim>
3876 const std::string &filename,
3877 const bool apply_all_indicators_to_manifolds)
3878{
3879#ifdef DEAL_II_TRILINOS_WITH_SEACAS
3880 // deal.II always uses double precision numbers for geometry
3881 int component_word_size = sizeof(double);
3882 // setting to zero uses the stored word size
3883 int floating_point_word_size = 0;
3884 float ex_version = 0.0;
3885
3886 const int ex_id = ex_open(filename.c_str(),
3887 EX_READ,
3888 &component_word_size,
3889 &floating_point_word_size,
3890 &ex_version);
3891 AssertThrow(ex_id > 0,
3892 ExcMessage("ExodusII failed to open the specified input file."));
3893
3894 // Read basic mesh information:
3895 std::vector<char> string_temp(MAX_LINE_LENGTH + 1, '\0');
3896 int mesh_dimension = 0;
3897 int n_nodes = 0;
3898 int n_elements = 0;
3899 int n_element_blocks = 0;
3900 int n_node_sets = 0;
3901 int n_side_sets = 0;
3902
3903 int ierr = ex_get_init(ex_id,
3904 string_temp.data(),
3905 &mesh_dimension,
3906 &n_nodes,
3907 &n_elements,
3908 &n_element_blocks,
3909 &n_node_sets,
3910 &n_side_sets);
3911 AssertThrowExodusII(ierr);
3912 AssertDimension(mesh_dimension, spacedim);
3913
3914 // Read nodes:
3915 //
3916 // Even if there is a node numbering array the values stored inside the
3917 // ExodusII file must use the contiguous, internal ordering (see Section 4.5
3918 // of the manual - "Internal (contiguously numbered) node and element IDs
3919 // must be used for all data structures that contain node or element numbers
3920 // (IDs), including node set node lists, side set element lists, and element
3921 // connectivity.")
3922 std::vector<Point<spacedim>> vertices;
3923 vertices.reserve(n_nodes);
3924 {
3925 std::vector<double> xs(n_nodes);
3926 std::vector<double> ys(n_nodes);
3927 std::vector<double> zs(n_nodes);
3928
3929 ierr = ex_get_coord(ex_id, xs.data(), ys.data(), zs.data());
3930 AssertThrowExodusII(ierr);
3931
3932 for (int vertex_n = 0; vertex_n < n_nodes; ++vertex_n)
3933 {
3934 switch (spacedim)
3935 {
3936 case 1:
3937 vertices.emplace_back(xs[vertex_n]);
3938 break;
3939 case 2:
3940 vertices.emplace_back(xs[vertex_n], ys[vertex_n]);
3941 break;
3942 case 3:
3943 vertices.emplace_back(xs[vertex_n], ys[vertex_n], zs[vertex_n]);
3944 break;
3945 default:
3946 Assert(spacedim <= 3, ExcNotImplemented());
3947 }
3948 }
3949 }
3950
3951 std::vector<int> element_block_ids(n_element_blocks);
3952 ierr = ex_get_ids(ex_id, EX_ELEM_BLOCK, element_block_ids.data());
3953 AssertThrowExodusII(ierr);
3954
3955 std::vector<CellData<dim>> cells;
3956 cells.reserve(n_elements);
3957 // Elements are grouped together by same reference cell type in element
3958 // blocks. There may be multiple blocks for a single reference cell type,
3959 // but "each element block may contain only one element type".
3960 for (const int element_block_id : element_block_ids)
3961 {
3962 std::fill(string_temp.begin(), string_temp.end(), '\0');
3963 int n_block_elements = 0;
3964 int n_nodes_per_element = 0;
3965 int n_edges_per_element = 0;
3966 int n_faces_per_element = 0;
3967 int n_attributes_per_element = 0;
3968
3969 // Extract element data.
3970 ierr = ex_get_block(ex_id,
3971 EX_ELEM_BLOCK,
3972 element_block_id,
3973 string_temp.data(),
3974 &n_block_elements,
3975 &n_nodes_per_element,
3976 &n_edges_per_element,
3977 &n_faces_per_element,
3978 &n_attributes_per_element);
3979 AssertThrowExodusII(ierr);
3980 const ReferenceCell type =
3981 exodusii_name_to_type(string_temp.data(), n_nodes_per_element);
3982 AssertThrow(type.get_dimension() == dim,
3983 ExcMessage(
3984 "The ExodusII block " + std::to_string(element_block_id) +
3985 " with element type " + std::string(string_temp.data()) +
3986 " has dimension " + std::to_string(type.get_dimension()) +
3987 ", which does not match the topological mesh dimension " +
3988 std::to_string(dim) + "."));
3989
3990 // The number of nodes per element may be larger than what we want to
3991 // read - for example, if the Exodus file contains a QUAD9 element, we
3992 // only want to read the first four values and ignore the rest.
3993 Assert(int(type.n_vertices()) <= n_nodes_per_element, ExcInternalError());
3994
3995 std::vector<int> connection(n_nodes_per_element * n_block_elements);
3996 ierr = ex_get_conn(ex_id,
3997 EX_ELEM_BLOCK,
3998 element_block_id,
3999 connection.data(),
4000 nullptr,
4001 nullptr);
4002 AssertThrowExodusII(ierr);
4003
4004 for (unsigned int elem_n = 0; elem_n < connection.size();
4005 elem_n += n_nodes_per_element)
4006 {
4007 CellData<dim> cell(type.n_vertices());
4008 for (const unsigned int i : type.vertex_indices())
4009 {
4011 connection[elem_n + i] - 1;
4012 }
4013 cell.material_id = element_block_id;
4014 cells.push_back(std::move(cell));
4015 }
4016 }
4017
4018 // Extract boundary data.
4019 auto pair = read_exodusii_sidesets<dim, spacedim>(
4020 ex_id, n_side_sets, cells, apply_all_indicators_to_manifolds);
4021 ierr = ex_close(ex_id);
4022 AssertThrowExodusII(ierr);
4023
4024 apply_grid_fixup_functions(vertices, cells, pair.first);
4025 tria->create_triangulation(vertices, cells, pair.first);
4026 ExodusIIData out;
4027 out.id_to_sideset_ids = std::move(pair.second);
4028 return out;
4029#else
4030 (void)filename;
4031 (void)apply_all_indicators_to_manifolds;
4032 AssertThrow(false, ExcNeedsExodusII());
4033 return {};
4034#endif
4035}
4036
4037
4038template <int dim, int spacedim>
4039void
4041{
4042 std::string line;
4043 while (in)
4044 {
4045 // get line
4046 getline(in, line);
4047
4048 // check if this is a line that
4049 // consists only of spaces, and
4050 // if not put the whole thing
4051 // back and return
4052 if (std::find_if(line.begin(), line.end(), [](const char c) {
4053 return c != ' ';
4054 }) != line.end())
4055 {
4056 in.putback('\n');
4057 for (int i = line.size() - 1; i >= 0; --i)
4058 in.putback(line[i]);
4059 return;
4060 }
4061
4062 // else: go on with next line
4063 }
4064}
4065
4066
4067
4068template <int dim, int spacedim>
4069void
4071 const char comment_start)
4072{
4073 char c;
4074 // loop over the following comment
4075 // lines
4076 while (in.get(c) && c == comment_start)
4077 // loop over the characters after
4078 // the comment starter
4079 while (in.get() != '\n')
4080 ;
4081
4082
4083 // put back first character of
4084 // first non-comment line
4085 if (in)
4086 in.putback(c);
4087
4088 // at last: skip additional empty lines, if present
4089 skip_empty_lines(in);
4090}
4091
4092
4093
4094template <int dim, int spacedim>
4095void
4097 const std::vector<CellData<dim>> & /*cells*/,
4098 const std::vector<Point<spacedim>> & /*vertices*/,
4099 std::ostream & /*out*/)
4100{
4102}
4103
4104
4105
4106template <>
4107void
4109 const std::vector<Point<2>> &vertices,
4110 std::ostream &out)
4111{
4112 double min_x = vertices[cells[0].vertices[0]][0],
4113 max_x = vertices[cells[0].vertices[0]][0],
4114 min_y = vertices[cells[0].vertices[0]][1],
4115 max_y = vertices[cells[0].vertices[0]][1];
4116
4117 for (unsigned int i = 0; i < cells.size(); ++i)
4118 {
4119 for (const auto vertex : cells[i].vertices)
4120 {
4121 const Point<2> &p = vertices[vertex];
4122
4123 if (p[0] < min_x)
4124 min_x = p[0];
4125 if (p[0] > max_x)
4126 max_x = p[0];
4127 if (p[1] < min_y)
4128 min_y = p[1];
4129 if (p[1] > max_y)
4130 max_y = p[1];
4131 }
4132
4133 out << "# cell " << i << std::endl;
4134 Point<2> center;
4135 for (const auto vertex : cells[i].vertices)
4136 center += vertices[vertex];
4137 center /= 4;
4138
4139 out << "set label \"" << i << "\" at " << center[0] << ',' << center[1]
4140 << " center" << std::endl;
4141
4142 // first two line right direction
4143 for (unsigned int f = 0; f < 2; ++f)
4144 out << "set arrow from " << vertices[cells[i].vertices[f]][0] << ','
4145 << vertices[cells[i].vertices[f]][1] << " to "
4146 << vertices[cells[i].vertices[(f + 1) % 4]][0] << ','
4147 << vertices[cells[i].vertices[(f + 1) % 4]][1] << std::endl;
4148 // other two lines reverse direction
4149 for (unsigned int f = 2; f < 4; ++f)
4150 out << "set arrow from " << vertices[cells[i].vertices[(f + 1) % 4]][0]
4151 << ',' << vertices[cells[i].vertices[(f + 1) % 4]][1] << " to "
4152 << vertices[cells[i].vertices[f]][0] << ','
4153 << vertices[cells[i].vertices[f]][1] << std::endl;
4154 out << std::endl;
4155 }
4156
4157
4158 out << std::endl
4159 << "set nokey" << std::endl
4160 << "pl [" << min_x << ':' << max_x << "][" << min_y << ':' << max_y
4161 << "] " << min_y << std::endl
4162 << "pause -1" << std::endl;
4163}
4164
4165
4166
4167template <>
4168void
4170 const std::vector<Point<3>> &vertices,
4171 std::ostream &out)
4172{
4173 for (const auto &cell : cells)
4174 {
4175 // line 0
4176 out << vertices[cell.vertices[0]] << std::endl
4177 << vertices[cell.vertices[1]] << std::endl
4178 << std::endl
4179 << std::endl;
4180 // line 1
4181 out << vertices[cell.vertices[1]] << std::endl
4182 << vertices[cell.vertices[2]] << std::endl
4183 << std::endl
4184 << std::endl;
4185 // line 2
4186 out << vertices[cell.vertices[3]] << std::endl
4187 << vertices[cell.vertices[2]] << std::endl
4188 << std::endl
4189 << std::endl;
4190 // line 3
4191 out << vertices[cell.vertices[0]] << std::endl
4192 << vertices[cell.vertices[3]] << std::endl
4193 << std::endl
4194 << std::endl;
4195 // line 4
4196 out << vertices[cell.vertices[4]] << std::endl
4197 << vertices[cell.vertices[5]] << std::endl
4198 << std::endl
4199 << std::endl;
4200 // line 5
4201 out << vertices[cell.vertices[5]] << std::endl
4202 << vertices[cell.vertices[6]] << std::endl
4203 << std::endl
4204 << std::endl;
4205 // line 6
4206 out << vertices[cell.vertices[7]] << std::endl
4207 << vertices[cell.vertices[6]] << std::endl
4208 << std::endl
4209 << std::endl;
4210 // line 7
4211 out << vertices[cell.vertices[4]] << std::endl
4212 << vertices[cell.vertices[7]] << std::endl
4213 << std::endl
4214 << std::endl;
4215 // line 8
4216 out << vertices[cell.vertices[0]] << std::endl
4217 << vertices[cell.vertices[4]] << std::endl
4218 << std::endl
4219 << std::endl;
4220 // line 9
4221 out << vertices[cell.vertices[1]] << std::endl
4222 << vertices[cell.vertices[5]] << std::endl
4223 << std::endl
4224 << std::endl;
4225 // line 10
4226 out << vertices[cell.vertices[2]] << std::endl
4227 << vertices[cell.vertices[6]] << std::endl
4228 << std::endl
4229 << std::endl;
4230 // line 11
4231 out << vertices[cell.vertices[3]] << std::endl
4232 << vertices[cell.vertices[7]] << std::endl
4233 << std::endl
4234 << std::endl;
4235 }
4236}
4237
4238
4239
4240template <int dim, int spacedim>
4241void
4242GridIn<dim, spacedim>::read(const std::string &filename, Format format)
4243{
4244 // Check early that the file actually exists and if not throw ExcFileNotOpen.
4245 AssertThrow(std::filesystem::exists(filename), ExcFileNotOpen(filename));
4246
4247 if (format == Default)
4248 {
4249 const std::string::size_type slashpos = filename.find_last_of('/');
4250 const std::string::size_type dotpos = filename.find_last_of('.');
4251 if (dotpos < filename.size() &&
4252 (dotpos > slashpos || slashpos == std::string::npos))
4253 {
4254 std::string ext = filename.substr(dotpos + 1);
4255 format = parse_format(ext);
4256 }
4257 }
4258
4259 if (format == assimp)
4260 {
4261 read_assimp(filename);
4262 }
4263 else if (format == exodusii)
4264 {
4265 read_exodusii(filename);
4266 }
4267 else
4268 {
4269 std::ifstream in(filename);
4270 read(in, format);
4271 }
4272}
4273
4274
4275template <int dim, int spacedim>
4276void
4277GridIn<dim, spacedim>::read(std::istream &in, Format format)
4278{
4279 if (format == Default)
4280 format = default_format;
4281
4282 switch (format)
4283 {
4284 case dbmesh:
4285 read_dbmesh(in);
4286 return;
4287
4288 case msh:
4289 read_msh(in);
4290 return;
4291
4292 case vtk:
4293 read_vtk(in);
4294 return;
4295
4296 case vtu:
4297 read_vtu(in);
4298 return;
4299
4300 case unv:
4301 read_unv(in);
4302 return;
4303
4304 case ucd:
4305 read_ucd(in);
4306 return;
4307
4308 case abaqus:
4309 read_abaqus(in);
4310 return;
4311
4312 case xda:
4313 read_xda(in);
4314 return;
4315
4316 case tecplot:
4317 read_tecplot(in);
4318 return;
4319
4320 case assimp:
4321 Assert(false,
4322 ExcMessage("There is no read_assimp(istream &) function. "
4323 "Use the read_assimp(string &filename, ...) "
4324 "functions, instead."));
4325 return;
4326
4327 case exodusii:
4328 Assert(false,
4329 ExcMessage("There is no read_exodusii(istream &) function. "
4330 "Use the read_exodusii(string &filename, ...) "
4331 "function, instead."));
4332 return;
4333
4334 case Default:
4335 break;
4336 }
4338}
4339
4340
4341
4342template <int dim, int spacedim>
4343std::string
4345{
4346 switch (format)
4347 {
4348 case dbmesh:
4349 return ".dbmesh";
4350 case exodusii:
4351 return ".e";
4352 case msh:
4353 return ".msh";
4354 case vtk:
4355 return ".vtk";
4356 case vtu:
4357 return ".vtu";
4358 case unv:
4359 return ".unv";
4360 case ucd:
4361 return ".inp";
4362 case abaqus:
4363 return ".inp"; // Typical suffix for Abaqus mesh files conflicts with
4364 // UCD.
4365 case xda:
4366 return ".xda";
4367 case tecplot:
4368 return ".dat";
4369 default:
4371 return ".unknown_format";
4372 }
4373}
4374
4375
4376
4377template <int dim, int spacedim>
4379GridIn<dim, spacedim>::parse_format(const std::string &format_name)
4380{
4381 if (format_name == "dbmesh")
4382 return dbmesh;
4383
4384 if (format_name == "exodusii")
4385 return exodusii;
4386
4387 if (format_name == "msh")
4388 return msh;
4389
4390 if (format_name == "unv")
4391 return unv;
4392
4393 if (format_name == "vtk")
4394 return vtk;
4395
4396 if (format_name == "vtu")
4397 return vtu;
4398
4399 // This is also the typical extension of Abaqus input files.
4400 if (format_name == "inp")
4401 return ucd;
4402
4403 if (format_name == "ucd")
4404 return ucd;
4405
4406 if (format_name == "xda")
4407 return xda;
4408
4409 if (format_name == "tecplot")
4410 return tecplot;
4411
4412 if (format_name == "dat")
4413 return tecplot;
4414
4415 if (format_name == "plt")
4416 // Actually, this is the extension for the
4417 // tecplot binary format, which we do not
4418 // support right now. However, some people
4419 // tend to create tecplot ascii files with
4420 // the extension 'plt' instead of
4421 // 'dat'. Thus, include this extension
4422 // here. If it actually is a binary file,
4423 // the read_tecplot() function will fail
4424 // and throw an exception, anyway.
4425 return tecplot;
4426
4427 AssertThrow(false, ExcInvalidState());
4428 // return something weird
4429 return Format(Default);
4430}
4431
4432
4433
4434template <int dim, int spacedim>
4435std::string
4437{
4438 return "dbmesh|exodusii|msh|unv|vtk|vtu|ucd|abaqus|xda|tecplot|assimp";
4439}
4440
4441
4442
4443namespace
4444{
4445 template <int dim, int spacedim>
4446 Abaqus_to_UCD<dim, spacedim>::Abaqus_to_UCD()
4447 : tolerance(5e-16) // Used to offset Cubit tolerance error when outputting
4448 // value close to zero
4449 {
4450 AssertThrow(spacedim == 2 || spacedim == 3, ExcNotImplemented());
4451 }
4452
4453
4454
4455 // Convert from a string to some other data type
4456 // Reference: http://www.codeguru.com/forum/showthread.php?t=231054
4457 template <class T>
4458 bool
4459 from_string(T &t, const std::string &s, std::ios_base &(*f)(std::ios_base &))
4460 {
4461 std::istringstream iss(s);
4462 return !(iss >> f >> t).fail();
4463 }
4464
4465
4466
4467 // Extract an integer from a string
4468 int
4469 extract_int(const std::string &s)
4470 {
4471 std::string tmp;
4472 for (const char c : s)
4473 {
4474 if (isdigit(c) != 0)
4475 {
4476 tmp += c;
4477 }
4478 }
4479
4480 int number = 0;
4481 from_string(number, tmp, std::dec);
4482 return number;
4483 }
4484
4485
4486
4487 template <int dim, int spacedim>
4488 void
4489 Abaqus_to_UCD<dim, spacedim>::read_in_abaqus(std::istream &input_stream)
4490 {
4491 // References:
4492 // http://www.egr.msu.edu/software/abaqus/Documentation/docs/v6.7/books/usb/default.htm?startat=pt01ch02.html
4493 // http://www.cprogramming.com/tutorial/string.html
4494
4495 AssertThrow(input_stream.fail() == false, ExcIO());
4496 std::string line;
4497
4498 while (std::getline(input_stream, line))
4499 {
4500 cont:
4501 std::transform(line.begin(), line.end(), line.begin(), ::toupper);
4502
4503 if (line.compare("*HEADING") == 0 || line.compare(0, 2, "**") == 0 ||
4504 line.compare(0, 5, "*PART") == 0)
4505 {
4506 // Skip header and comments
4507 while (std::getline(input_stream, line))
4508 {
4509 if (line[0] == '*')
4510 goto cont; // My eyes, they burn!
4511 }
4512 }
4513 else if (line.compare(0, 5, "*NODE") == 0)
4514 {
4515 // Extract list of vertices
4516 // Header line might be:
4517 // *NODE, NSET=ALLNODES
4518 // *NODE
4519
4520 // Contains lines in the form:
4521 // Index, x, y, z
4522 while (std::getline(input_stream, line))
4523 {
4524 if (line[0] == '*')
4525 goto cont;
4526
4527 std::vector<double> node(spacedim + 1);
4528
4529 std::istringstream iss(line);
4530 char comma;
4531 for (unsigned int i = 0; i < spacedim + 1; ++i)
4532 iss >> node[i] >> comma;
4533
4534 node_list.push_back(node);
4535 }
4536 }
4537 else if (line.compare(0, 8, "*ELEMENT") == 0)
4538 {
4539 // Element construction.
4540 // There are different header formats, the details
4541 // of which we're not particularly interested in except
4542 // whether they represent quads or hexahedrals.
4543 // *ELEMENT, TYPE=S4R, ELSET=EB<material id>
4544 // *ELEMENT, TYPE=C3d8R, ELSET=EB<material id>
4545 // *ELEMENT, TYPE=C3d8
4546 // Elements itself (n=4 or n=8):
4547 // Index, i[0], ..., i[n]
4548
4549 int material = 0;
4550 // Scan for material id
4551 {
4552 const std::string before_material = "ELSET=EB";
4553 const std::size_t idx = line.find(before_material);
4554 if (idx != std::string::npos)
4555 {
4556 from_string(material,
4557 line.substr(idx + before_material.size()),
4558 std::dec);
4559 }
4560 }
4561
4562 // Read ELEMENT definition
4563 while (std::getline(input_stream, line))
4564 {
4565 if (line[0] == '*')
4566 goto cont;
4567
4568 std::istringstream iss(line);
4569 char comma;
4570
4571 // We will store the material id in the zeroth entry of the
4572 // vector and the rest of the elements represent the global
4573 // node numbers
4574 const unsigned int n_data_per_cell =
4576 std::vector<double> cell(n_data_per_cell);
4577 for (unsigned int i = 0; i < n_data_per_cell; ++i)
4578 iss >> cell[i] >> comma;
4579
4580 // Overwrite cell index from file by material
4581 cell[0] = static_cast<double>(material);
4582 cell_list.push_back(cell);
4583 }
4584 }
4585 else if (line.compare(0, 8, "*SURFACE") == 0)
4586 {
4587 // Extract the definitions of boundary surfaces
4588 // Old format from Cubit:
4589 // *SURFACE, NAME=SS<boundary indicator>
4590 // <element index>, S<face number>
4591 // Abaqus default format:
4592 // *SURFACE, TYPE=ELEMENT, NAME=SURF-<indicator>
4593
4594 // Get name of the surface and extract id from it;
4595 // this will be the boundary indicator
4596 const std::string name_key = "NAME=";
4597 const std::size_t name_idx_start =
4598 line.find(name_key) + name_key.size();
4599 std::size_t name_idx_end = line.find(',', name_idx_start);
4600 if (name_idx_end == std::string::npos)
4601 {
4602 name_idx_end = line.size();
4603 }
4604 const int b_indicator = extract_int(
4605 line.substr(name_idx_start, name_idx_end - name_idx_start));
4606
4607 // Read SURFACE definition
4608 // Note that the orientation of the faces is embedded within the
4609 // definition of each "set" of faces that comprise the surface
4610 // These are either marked by an "S" or "E" in 3d or 2d
4611 // respectively.
4612 while (std::getline(input_stream, line))
4613 {
4614 if (line[0] == '*')
4615 goto cont;
4616
4617 // Change all characters to upper case
4618 std::transform(line.begin(),
4619 line.end(),
4620 line.begin(),
4621 ::toupper);
4622
4623 // Surface can be created from ELSET, or directly from cells
4624 // If elsets_list contains a key with specific name - refers
4625 // to that ELSET, otherwise refers to cell
4626 std::istringstream iss(line);
4627 int el_idx;
4628 int face_number;
4629 char temp;
4630
4631 // Get relevant faces, taking into account the element
4632 // orientation
4633 std::vector<double> quad_node_list;
4634 const std::string elset_name = line.substr(0, line.find(','));
4635 if (elsets_list.count(elset_name) != 0)
4636 {
4637 // Surface refers to ELSET
4638 std::string stmp;
4639 iss >> stmp >> temp >> face_number;
4640
4641 const std::vector<int> cells = elsets_list[elset_name];
4642 for (const int cell : cells)
4643 {
4644 el_idx = cell;
4645 quad_node_list =
4646 get_global_node_numbers(el_idx, face_number);
4647 quad_node_list.insert(quad_node_list.begin(),
4648 b_indicator);
4649
4650 face_list.push_back(quad_node_list);
4651 }
4652 }
4653 else
4654 {
4655 // Surface refers directly to elements
4656 char comma;
4657 iss >> el_idx >> comma >> temp >> face_number;
4658 quad_node_list =
4659 get_global_node_numbers(el_idx, face_number);
4660 quad_node_list.insert(quad_node_list.begin(), b_indicator);
4661
4662 face_list.push_back(quad_node_list);
4663 }
4664 }
4665 }
4666 else if (line.compare(0, 6, "*ELSET") == 0)
4667 {
4668 // Get ELSET name.
4669 // Materials are attached to elsets with specific name
4670 std::string elset_name;
4671 {
4672 const std::string elset_key = "*ELSET, ELSET=";
4673 const std::size_t idx = line.find(elset_key);
4674 if (idx != std::string::npos)
4675 {
4676 const std::string comma = ",";
4677 const std::size_t first_comma = line.find(comma);
4678 const std::size_t second_comma =
4679 line.find(comma, first_comma + 1);
4680 const std::size_t elset_name_start =
4681 line.find(elset_key) + elset_key.size();
4682 elset_name = line.substr(elset_name_start,
4683 second_comma - elset_name_start);
4684 }
4685 }
4686
4687 // There are two possibilities of storing cells numbers in ELSET:
4688 // 1. If the header contains the 'GENERATE' keyword, then the next
4689 // line describes range of cells as:
4690 // cell_id_start, cell_id_end, cell_step
4691 // 2. If the header does not contain the 'GENERATE' keyword, then
4692 // the next lines contain cells numbers
4693 std::vector<int> elements;
4694 const std::size_t generate_idx = line.find("GENERATE");
4695 if (generate_idx != std::string::npos)
4696 {
4697 // Option (1)
4698 std::getline(input_stream, line);
4699 std::istringstream iss(line);
4700 char comma;
4701 int elid_start;
4702 int elid_end;
4703 int elis_step = 1; // Default if case stride not provided
4704
4705 // Some files don't have the stride size
4706 // Compare mesh test cases ./grids/abaqus/3d/other_simple.inp
4707 // to
4708 // ./grids/abaqus/2d/2d_test_abaqus.inp
4709 iss >> elid_start >> comma >> elid_end;
4710 AssertThrow(comma == ',',
4711 ExcMessage(
4712 std::string(
4713 "While reading an ABAQUS file, the reader "
4714 "expected a comma but found a <") +
4715 comma + "> in the line <" + line + ">."));
4717 elid_start <= elid_end,
4718 ExcMessage(
4719 std::string(
4720 "While reading an ABAQUS file, the reader encountered "
4721 "a GENERATE statement in which the upper bound <") +
4722 Utilities::int_to_string(elid_end) +
4723 "> for the element numbers is not larger or equal "
4724 "than the lower bound <" +
4725 Utilities::int_to_string(elid_start) + ">."));
4726
4727 // https://stackoverflow.com/questions/8046357/how-do-i-check-if-a-stringstream-variable-is-empty-null
4728 if (iss.rdbuf()->in_avail() != 0)
4729 iss >> comma >> elis_step;
4730 AssertThrow(comma == ',',
4731 ExcMessage(
4732 std::string(
4733 "While reading an ABAQUS file, the reader "
4734 "expected a comma but found a <") +
4735 comma + "> in the line <" + line + ">."));
4736
4737 for (int i = elid_start; i <= elid_end; i += elis_step)
4738 elements.push_back(i);
4739 elsets_list[elset_name] = elements;
4740
4741 std::getline(input_stream, line);
4742 }
4743 else
4744 {
4745 // Option (2)
4746 while (std::getline(input_stream, line))
4747 {
4748 if (line[0] == '*')
4749 break;
4750
4751 std::istringstream iss(line);
4752 char comma;
4753 int elid;
4754 while (!iss.eof())
4755 {
4756 iss >> elid >> comma;
4758 comma == ',',
4759 ExcMessage(
4760 std::string(
4761 "While reading an ABAQUS file, the reader "
4762 "expected a comma but found a <") +
4763 comma + "> in the line <" + line + ">."));
4764
4765 elements.push_back(elid);
4766 }
4767 }
4768
4769 elsets_list[elset_name] = elements;
4770 }
4771
4772 goto cont;
4773 }
4774 else if (line.compare(0, 5, "*NSET") == 0)
4775 {
4776 // Skip nodesets; we have no use for them
4777 while (std::getline(input_stream, line))
4778 {
4779 if (line[0] == '*')
4780 goto cont;
4781 }
4782 }
4783 else if (line.compare(0, 14, "*SOLID SECTION") == 0)
4784 {
4785 // The ELSET name, which describes a section for particular
4786 // material
4787 const std::string elset_key = "ELSET=";
4788 const std::size_t elset_start =
4789 line.find("ELSET=") + elset_key.size();
4790 const std::size_t elset_end = line.find(',', elset_start + 1);
4791 const std::string elset_name =
4792 line.substr(elset_start, elset_end - elset_start);
4793
4794 // Solid material definition.
4795 // We assume that material id is taken from material name,
4796 // eg. "Material-1" -> ID=1
4797 const std::string material_key = "MATERIAL=";
4798 const std::size_t last_equal =
4799 line.find("MATERIAL=") + material_key.size();
4800 const std::size_t material_id_start = line.find('-', last_equal);
4801 int material_id = 0;
4802 from_string(material_id,
4803 line.substr(material_id_start + 1),
4804 std::dec);
4805
4806 // Assign material id to cells
4807 const std::vector<int> &elset_cells = elsets_list[elset_name];
4808 for (const int elset_cell : elset_cells)
4809 {
4810 const int cell_id = elset_cell - 1;
4811 cell_list[cell_id][0] = material_id;
4812 }
4813 }
4814 // Note: All other lines / entries are ignored
4815 }
4816 }
4817
4818 template <int dim, int spacedim>
4819 std::vector<double>
4820 Abaqus_to_UCD<dim, spacedim>::get_global_node_numbers(
4821 const int face_cell_no,
4822 const int face_cell_face_no) const
4823 {
4824 std::vector<double> quad_node_list(GeometryInfo<dim>::vertices_per_face);
4825
4826 // These orderings were reverse engineered by hand and may
4827 // conceivably be erroneous.
4828 // TODO: Currently one test (2d unstructured mesh) in the test
4829 // suite fails, presumably because of an ordering issue.
4830 if (dim == 2)
4831 {
4832 if (face_cell_face_no == 1)
4833 {
4834 quad_node_list[0] = cell_list[face_cell_no - 1][1];
4835 quad_node_list[1] = cell_list[face_cell_no - 1][2];
4836 }
4837 else if (face_cell_face_no == 2)
4838 {
4839 quad_node_list[0] = cell_list[face_cell_no - 1][2];
4840 quad_node_list[1] = cell_list[face_cell_no - 1][3];
4841 }
4842 else if (face_cell_face_no == 3)
4843 {
4844 quad_node_list[0] = cell_list[face_cell_no - 1][3];
4845 quad_node_list[1] = cell_list[face_cell_no - 1][4];
4846 }
4847 else if (face_cell_face_no == 4)
4848 {
4849 quad_node_list[0] = cell_list[face_cell_no - 1][4];
4850 quad_node_list[1] = cell_list[face_cell_no - 1][1];
4851 }
4852 else
4853 {
4854 AssertThrow(face_cell_face_no <= 4,
4855 ExcMessage("Invalid face number in 2d"));
4856 }
4857 }
4858 else if (dim == 3)
4859 {
4860 if (face_cell_face_no == 1)
4861 {
4862 quad_node_list[0] = cell_list[face_cell_no - 1][1];
4863 quad_node_list[1] = cell_list[face_cell_no - 1][4];
4864 quad_node_list[2] = cell_list[face_cell_no - 1][3];
4865 quad_node_list[3] = cell_list[face_cell_no - 1][2];
4866 }
4867 else if (face_cell_face_no == 2)
4868 {
4869 quad_node_list[0] = cell_list[face_cell_no - 1][5];
4870 quad_node_list[1] = cell_list[face_cell_no - 1][8];
4871 quad_node_list[2] = cell_list[face_cell_no - 1][7];
4872 quad_node_list[3] = cell_list[face_cell_no - 1][6];
4873 }
4874 else if (face_cell_face_no == 3)
4875 {
4876 quad_node_list[0] = cell_list[face_cell_no - 1][1];
4877 quad_node_list[1] = cell_list[face_cell_no - 1][2];
4878 quad_node_list[2] = cell_list[face_cell_no - 1][6];
4879 quad_node_list[3] = cell_list[face_cell_no - 1][5];
4880 }
4881 else if (face_cell_face_no == 4)
4882 {
4883 quad_node_list[0] = cell_list[face_cell_no - 1][2];
4884 quad_node_list[1] = cell_list[face_cell_no - 1][3];
4885 quad_node_list[2] = cell_list[face_cell_no - 1][7];
4886 quad_node_list[3] = cell_list[face_cell_no - 1][6];
4887 }
4888 else if (face_cell_face_no == 5)
4889 {
4890 quad_node_list[0] = cell_list[face_cell_no - 1][3];
4891 quad_node_list[1] = cell_list[face_cell_no - 1][4];
4892 quad_node_list[2] = cell_list[face_cell_no - 1][8];
4893 quad_node_list[3] = cell_list[face_cell_no - 1][7];
4894 }
4895 else if (face_cell_face_no == 6)
4896 {
4897 quad_node_list[0] = cell_list[face_cell_no - 1][1];
4898 quad_node_list[1] = cell_list[face_cell_no - 1][5];
4899 quad_node_list[2] = cell_list[face_cell_no - 1][8];
4900 quad_node_list[3] = cell_list[face_cell_no - 1][4];
4901 }
4902 else
4903 {
4904 AssertThrow(face_cell_no <= 6,
4905 ExcMessage("Invalid face number in 3d"));
4906 }
4907 }
4908 else
4909 {
4910 AssertThrow(dim == 2 || dim == 3, ExcNotImplemented());
4911 }
4912
4913 return quad_node_list;
4914 }
4915
4916 template <int dim, int spacedim>
4917 void
4918 Abaqus_to_UCD<dim, spacedim>::write_out_avs_ucd(std::ostream &output) const
4919 {
4920 // References:
4921 // http://www.dealii.org/developer/doxygen/deal.II/structGeometryInfo.html
4922 // http://people.scs.fsu.edu/~burkardt/data/ucd/ucd.html
4923
4924 AssertThrow(output.fail() == false, ExcIO());
4925
4926 // save old formatting options
4927 const boost::io::ios_base_all_saver formatting_saver(output);
4928
4929 // Write out title - Note: No other commented text can be inserted below
4930 // the title in a UCD file
4931 output << "# Abaqus to UCD mesh conversion" << std::endl;
4932 output << "# Mesh type: AVS UCD" << std::endl;
4933
4934 // ========================================================
4935 // ASCII UCD File Format
4936 // The input file cannot contain blank lines or lines with leading blanks.
4937 // Comments, if present, must precede all data in the file.
4938 // Comments within the data will cause read errors.
4939 // The general order of the data is as follows:
4940 // 1. Numbers defining the overall structure, including the number of
4941 // nodes,
4942 // the number of cells, and the length of the vector of data associated
4943 // with the nodes, cells, and the model.
4944 // e.g. 1:
4945 // <num_nodes> <num_cells> <num_ndata> <num_cdata> <num_mdata>
4946 // e.g. 2:
4947 // n_elements = n_hex_cells + n_bc_quads + n_quad_cells +
4948 // n_bc_edges outfile.write(str(n_nodes) + " " + str(n_elements) +
4949 // " 0 0 0\n")
4950 // 2. For each node, its node id and the coordinates of that node in
4951 // space.
4952 // Node-ids must be integers, but any number including non sequential
4953 // numbers can be used. Mid-edge nodes are treated like any other node.
4954 // 3. For each cell: its cell-id, material, cell type (hexahedral,
4955 // pyramid,
4956 // etc.), and the list of node-ids that correspond to each of the
4957 // cell's vertices. The below table specifies the different cell types
4958 // and the keyword used to represent them in the file.
4959
4960 // Write out header
4961 output << node_list.size() << "\t" << (cell_list.size() + face_list.size())
4962 << "\t0\t0\t0" << std::endl;
4963
4964 output.width(16);
4965 output.precision(8);
4966
4967 // Write out node numbers
4968 // Loop over all nodes
4969 for (const auto &node : node_list)
4970 {
4971 // Node number
4972 output << node[0] << "\t";
4973
4974 // Node coordinates
4975 output.setf(std::ios::scientific, std::ios::floatfield);
4976 for (unsigned int jj = 1; jj < spacedim + 1; ++jj)
4977 {
4978 // invoke tolerance -> set points close to zero equal to zero
4979 if (std::abs(node[jj]) > tolerance)
4980 output << static_cast<double>(node[jj]) << "\t";
4981 else
4982 output << 0.0 << "\t";
4983 }
4984 if (spacedim == 2)
4985 output << 0.0 << "\t";
4986
4987 output << std::endl;
4988 output.unsetf(std::ios::floatfield);
4989 }
4990
4991 // Write out cell node numbers
4992 for (unsigned int ii = 0; ii < cell_list.size(); ++ii)
4993 {
4994 output << ii + 1 << "\t" << cell_list[ii][0] << "\t"
4995 << (dim == 2 ? "quad" : "hex") << "\t";
4996 for (unsigned int jj = 1; jj < GeometryInfo<dim>::vertices_per_cell + 1;
4997 ++jj)
4998 output << cell_list[ii][jj] << "\t";
4999
5000 output << std::endl;
5001 }
5002
5003 // Write out quad node numbers
5004 for (unsigned int ii = 0; ii < face_list.size(); ++ii)
5005 {
5006 output << ii + 1 << "\t" << face_list[ii][0] << "\t"
5007 << (dim == 2 ? "line" : "quad") << "\t";
5008 for (unsigned int jj = 1; jj < GeometryInfo<dim>::vertices_per_face + 1;
5009 ++jj)
5010 output << face_list[ii][jj] << "\t";
5011
5012 output << std::endl;
5013 }
5014 }
5015} // namespace
5016
5017
5018// explicit instantiations
5019#include "grid_in.inst"
5020
void read_vtk(std::istream &in)
Definition grid_in.cc:162
GridIn()
Definition grid_in.cc:136
static void skip_empty_lines(std::istream &in)
Definition grid_in.cc:4040
void read_assimp(const std::string &filename, const unsigned int mesh_index=numbers::invalid_unsigned_int, const bool remove_duplicates=true, const double tol=1e-12, const bool ignore_unsupported_element_types=true)
Definition grid_in.cc:3504
void read_abaqus(std::istream &in, const bool apply_all_indicators_to_manifolds=false)
Definition grid_in.cc:1246
static std::string default_suffix(const Format format)
Definition grid_in.cc:4344
void read_xda(std::istream &in)
Definition grid_in.cc:1463
void read_comsol_mphtxt(std::istream &in)
Definition grid_in.cc:1527
static void skip_comment_lines(std::istream &in, const char comment_start)
Definition grid_in.cc:4070
void attach_triangulation(Triangulation< dim, spacedim > &tria)
Definition grid_in.cc:153
const std::map< std::string, Vector< double > > & get_cell_data() const
Definition grid_in.cc:658
void read_msh(std::istream &in)
Definition grid_in.cc:2083
static Format parse_format(const std::string &format_name)
Definition grid_in.cc:4379
void read_vtu(std::istream &in)
Definition grid_in.cc:665
void read_tecplot(std::istream &in)
Definition grid_in.cc:3495
ExodusIIData read_exodusii(const std::string &filename, const bool apply_all_indicators_to_manifolds=false)
Definition grid_in.cc:3875
void read_dbmesh(std::istream &in)
Definition grid_in.cc:1302
void read_ucd(std::istream &in, const bool apply_all_indicators_to_manifolds=false)
Definition grid_in.cc:992
void read(std::istream &in, Format format=Default)
Definition grid_in.cc:4277
static void debug_output_grid(const std::vector< CellData< dim > > &cells, const std::vector< Point< spacedim > > &vertices, std::ostream &out)
Definition grid_in.cc:4096
static std::string get_format_names()
Definition grid_in.cc:4436
void read_unv(std::istream &in)
Definition grid_in.cc:692
static void parse_tecplot_header(std::string &header, std::vector< unsigned int > &tecplot2deal, unsigned int &n_vars, unsigned int &n_vertices, unsigned int &n_cells, std::vector< unsigned int > &IJK, bool &structured, bool &blocked)
Definition grid_in.cc:3030
Definition point.h:111
std_cxx20::ranges::iota_view< unsigned int, unsigned int > vertex_indices() const
unsigned int n_vertices() const
unsigned int exodusii_vertex_to_deal_vertex(const unsigned int vertex_n) const
unsigned int face_to_cell_vertices(const unsigned int face, const unsigned int vertex, const types::geometric_orientation face_orientation) const
unsigned int get_dimension() const
ReferenceCell face_reference_cell(const unsigned int face_no) const
unsigned int exodusii_face_to_deal_face(const unsigned int face_n) const
static ReferenceCell n_vertices_to_type(const int dim, const unsigned int n_vertices)
virtual void reinit(const size_type N, const bool omit_zeroing_entries=false)
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:498
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:499
#define DEAL_II_FALLTHROUGH
Definition config.h:233
Point< 2 > first
Definition grid_out.cc:4629
unsigned int vertex_indices[2]
static ::ExceptionBase & ExcIO()
static ::ExceptionBase & ExcFileNotOpen(std::string arg1)
static ::ExceptionBase & ExcNeedsAssimp()
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
static ::ExceptionBase & ExcImpossibleInDim(int arg1)
static ::ExceptionBase & ExcNeedsExodusII()
#define AssertDimension(dim1, dim2)
#define AssertThrowExodusII(error_code)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcIndexRange(std::size_t arg1, std::size_t arg2, std::size_t arg3)
static ::ExceptionBase & ExcInvalidState()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
void consistently_order_cells(std::vector< CellData< dim > > &cells)
#define DEAL_II_ASSERT_UNREACHABLE()
#define DEAL_II_NOT_IMPLEMENTED()
std::vector< index_type > data
Definition mpi.cc:735
std::size_t size
Definition mpi.cc:734
void delete_unused_vertices(std::vector< Point< spacedim > > &vertices, std::vector< CellData< dim > > &cells, SubCellData &subcelldata)
std::size_t invert_cells_with_negative_measure(const std::vector< Point< spacedim > > &all_vertices, std::vector< CellData< dim > > &cells)
void delete_duplicated_vertices(std::vector< Point< spacedim > > &all_vertices, std::vector< CellData< dim > > &cells, SubCellData &subcelldata, std::vector< unsigned int > &considered_vertices, const double tol=1e-12)
void to_value(const std::string &s, T &t)
Definition patterns.h:2459
constexpr const ReferenceCell Tetrahedron
constexpr const ReferenceCell Quadrilateral
constexpr const ReferenceCell Wedge
constexpr const ReferenceCell Pyramid
constexpr const ReferenceCell Invalid
constexpr const ReferenceCell Triangle
constexpr const ReferenceCell Hexahedron
constexpr const ReferenceCell Vertex
constexpr const ReferenceCell Line
std::pair< int, unsigned int > get_integer_at_position(const std::string &name, const unsigned int position)
Definition utilities.cc:847
std::vector< unsigned char > decode_base64(const std::string &base64_input)
Definition utilities.cc:446
std::vector< std::string > break_text_into_lines(const std::string &original_text, const unsigned int width, const char delimiter=' ')
Definition utilities.cc:755
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition utilities.cc:470
bool match_at_string_start(const std::string &name, const std::string &pattern)
Definition utilities.cc:832
std::string decompress(const std::string &compressed_input)
Definition utilities.cc:411
const types::material_id invalid_material_id
Definition types.h:289
const types::boundary_id internal_face_boundary_id
Definition types.h:324
static const unsigned int invalid_unsigned_int
Definition types.h:232
const types::manifold_id flat_manifold_id
Definition types.h:337
::VectorizedArray< Number, width > min(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
unsigned int material_id
Definition types.h:176
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation
std::vector< unsigned int > vertices
Definition cell_data.h:85
types::material_id material_id
Definition cell_data.h:104
static std_cxx20::ranges::iota_view< unsigned int, unsigned int > vertex_indices()
std::vector< std::vector< int > > id_to_sideset_ids
Definition grid_in.h:690
std::vector< CellData< 2 > > boundary_quads
Definition cell_data.h:248
bool check_consistency(const unsigned int dim) const
std::vector< CellData< 1 > > boundary_lines
Definition cell_data.h:232