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